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
nghttp2_buf_init(nghttp2_buf * buf)32 void nghttp2_buf_init(nghttp2_buf *buf)
33 {
34 buf->begin = NULL;
35 buf->end = NULL;
36 buf->pos = NULL;
37 buf->last = NULL;
38 buf->mark = NULL;
39 }
40
nghttp2_buf_init2(nghttp2_buf * buf,size_t initial,nghttp2_mem * mem)41 int nghttp2_buf_init2(nghttp2_buf *buf, size_t initial, nghttp2_mem *mem)
42 {
43 nghttp2_buf_init(buf);
44 return nghttp2_buf_reserve(buf, initial, mem);
45 }
46
nghttp2_buf_free(nghttp2_buf * buf,nghttp2_mem * mem)47 void nghttp2_buf_free(nghttp2_buf *buf, nghttp2_mem *mem)
48 {
49 if (buf == NULL) {
50 return;
51 }
52
53 nghttp2_mem_free(mem, buf->begin);
54 buf->begin = NULL;
55 }
56
nghttp2_buf_reserve(nghttp2_buf * buf,size_t new_cap,nghttp2_mem * mem)57 int nghttp2_buf_reserve(nghttp2_buf *buf, size_t new_cap, nghttp2_mem *mem)
58 {
59 uint8_t *ptr;
60 size_t cap;
61
62 cap = nghttp2_buf_cap(buf);
63
64 if (cap >= new_cap) {
65 return 0;
66 }
67
68 new_cap = nghttp2_max(new_cap, cap * 2);
69
70 ptr = nghttp2_mem_realloc(mem, buf->begin, new_cap);
71 if (ptr == NULL) {
72 return NGHTTP2_ERR_NOMEM;
73 }
74
75 buf->pos = ptr + (buf->pos - buf->begin);
76 buf->last = ptr + (buf->last - buf->begin);
77 buf->mark = ptr + (buf->mark - buf->begin);
78 buf->begin = ptr;
79 buf->end = ptr + new_cap;
80
81 return 0;
82 }
83
nghttp2_buf_reset(nghttp2_buf * buf)84 void nghttp2_buf_reset(nghttp2_buf *buf)
85 {
86 buf->pos = buf->last = buf->mark = buf->begin;
87 }
88
nghttp2_buf_wrap_init(nghttp2_buf * buf,uint8_t * begin,size_t len)89 void nghttp2_buf_wrap_init(nghttp2_buf *buf, uint8_t *begin, size_t len)
90 {
91 buf->begin = buf->pos = buf->last = buf->mark = begin;
92 buf->end = begin + len;
93 }
94
buf_chain_new(nghttp2_buf_chain ** chain,size_t chunk_length,nghttp2_mem * mem)95 static int buf_chain_new(nghttp2_buf_chain **chain, size_t chunk_length,
96 nghttp2_mem *mem)
97 {
98 int rv;
99
100 *chain = nghttp2_mem_malloc(mem, sizeof(nghttp2_buf_chain));
101 if (*chain == NULL) {
102 return NGHTTP2_ERR_NOMEM;
103 }
104
105 (*chain)->next = NULL;
106
107 rv = nghttp2_buf_init2(&(*chain)->buf, chunk_length, mem);
108 if (rv != 0) {
109 nghttp2_mem_free(mem, *chain);
110 return NGHTTP2_ERR_NOMEM;
111 }
112
113 return 0;
114 }
115
buf_chain_del(nghttp2_buf_chain * chain,nghttp2_mem * mem)116 static void buf_chain_del(nghttp2_buf_chain *chain, nghttp2_mem *mem)
117 {
118 nghttp2_buf_free(&chain->buf, mem);
119 nghttp2_mem_free(mem, chain);
120 }
121
nghttp2_bufs_init(nghttp2_bufs * bufs,size_t chunk_length,size_t max_chunk,nghttp2_mem * mem)122 int nghttp2_bufs_init(nghttp2_bufs *bufs, size_t chunk_length, size_t max_chunk,
123 nghttp2_mem *mem)
124 {
125 return nghttp2_bufs_init2(bufs, chunk_length, max_chunk, 0, mem);
126 }
127
nghttp2_bufs_init2(nghttp2_bufs * bufs,size_t chunk_length,size_t max_chunk,size_t offset,nghttp2_mem * mem)128 int nghttp2_bufs_init2(nghttp2_bufs *bufs, size_t chunk_length,
129 size_t max_chunk, size_t offset, nghttp2_mem *mem)
130 {
131 return nghttp2_bufs_init3(bufs, chunk_length, max_chunk, max_chunk, offset,
132 mem);
133 }
134
nghttp2_bufs_init3(nghttp2_bufs * bufs,size_t chunk_length,size_t max_chunk,size_t chunk_keep,size_t offset,nghttp2_mem * mem)135 int nghttp2_bufs_init3(nghttp2_bufs *bufs, size_t chunk_length,
136 size_t max_chunk, size_t chunk_keep, size_t offset,
137 nghttp2_mem *mem)
138 {
139 int rv;
140 nghttp2_buf_chain *chain;
141
142 if (chunk_keep == 0 || max_chunk < chunk_keep || chunk_length < offset) {
143 return NGHTTP2_ERR_INVALID_ARGUMENT;
144 }
145
146 rv = buf_chain_new(&chain, chunk_length, mem);
147 if (rv != 0) {
148 return rv;
149 }
150
151 bufs->mem = mem;
152 bufs->offset = offset;
153
154 bufs->head = chain;
155 bufs->cur = bufs->head;
156
157 nghttp2_buf_shift_right(&bufs->cur->buf, offset);
158
159 bufs->chunk_length = chunk_length;
160 bufs->chunk_used = 1;
161 bufs->max_chunk = max_chunk;
162 bufs->chunk_keep = chunk_keep;
163
164 return 0;
165 }
166
nghttp2_bufs_realloc(nghttp2_bufs * bufs,size_t chunk_length)167 int nghttp2_bufs_realloc(nghttp2_bufs *bufs, size_t chunk_length)
168 {
169 int rv;
170 nghttp2_buf_chain *chain;
171
172 if (chunk_length < bufs->offset) {
173 return NGHTTP2_ERR_INVALID_ARGUMENT;
174 }
175
176 rv = buf_chain_new(&chain, chunk_length, bufs->mem);
177 if (rv != 0) {
178 return rv;
179 }
180
181 nghttp2_bufs_free(bufs);
182
183 bufs->head = chain;
184 bufs->cur = bufs->head;
185
186 nghttp2_buf_shift_right(&bufs->cur->buf, bufs->offset);
187
188 bufs->chunk_length = chunk_length;
189 bufs->chunk_used = 1;
190
191 return 0;
192 }
193
nghttp2_bufs_free(nghttp2_bufs * bufs)194 void nghttp2_bufs_free(nghttp2_bufs *bufs)
195 {
196 nghttp2_buf_chain *chain, *next_chain;
197
198 if (bufs == NULL) {
199 return;
200 }
201
202 for (chain = bufs->head; chain;) {
203 next_chain = chain->next;
204
205 buf_chain_del(chain, bufs->mem);
206
207 chain = next_chain;
208 }
209
210 bufs->head = NULL;
211 }
212
nghttp2_bufs_wrap_init(nghttp2_bufs * bufs,uint8_t * begin,size_t len,nghttp2_mem * mem)213 int nghttp2_bufs_wrap_init(nghttp2_bufs *bufs, uint8_t *begin, size_t len,
214 nghttp2_mem *mem)
215 {
216 nghttp2_buf_chain *chain;
217
218 chain = nghttp2_mem_malloc(mem, sizeof(nghttp2_buf_chain));
219 if (chain == NULL) {
220 return NGHTTP2_ERR_NOMEM;
221 }
222
223 chain->next = NULL;
224
225 nghttp2_buf_wrap_init(&chain->buf, begin, len);
226
227 bufs->mem = mem;
228 bufs->offset = 0;
229
230 bufs->head = chain;
231 bufs->cur = bufs->head;
232
233 bufs->chunk_length = len;
234 bufs->chunk_used = 1;
235 bufs->max_chunk = 1;
236 bufs->chunk_keep = 1;
237
238 return 0;
239 }
240
nghttp2_bufs_wrap_init2(nghttp2_bufs * bufs,const nghttp2_vec * vec,size_t veclen,nghttp2_mem * mem)241 int nghttp2_bufs_wrap_init2(nghttp2_bufs *bufs, const nghttp2_vec *vec,
242 size_t veclen, nghttp2_mem *mem)
243 {
244 size_t i = 0;
245 nghttp2_buf_chain *cur_chain;
246 nghttp2_buf_chain *head_chain;
247 nghttp2_buf_chain **dst_chain = &head_chain;
248
249 if (veclen == 0) {
250 return nghttp2_bufs_wrap_init(bufs, NULL, 0, mem);
251 }
252
253 head_chain = nghttp2_mem_malloc(mem, sizeof(nghttp2_buf_chain) * veclen);
254 if (head_chain == NULL) {
255 return NGHTTP2_ERR_NOMEM;
256 }
257
258 for (i = 0; i < veclen; ++i) {
259 cur_chain = &head_chain[i];
260 cur_chain->next = NULL;
261 nghttp2_buf_wrap_init(&cur_chain->buf, vec[i].base, vec[i].len);
262
263 *dst_chain = cur_chain;
264 dst_chain = &cur_chain->next;
265 }
266
267 bufs->mem = mem;
268 bufs->offset = 0;
269
270 bufs->head = head_chain;
271 bufs->cur = bufs->head;
272
273 /* We don't use chunk_length since no allocation is expected. */
274 bufs->chunk_length = 0;
275 bufs->chunk_used = veclen;
276 bufs->max_chunk = veclen;
277 bufs->chunk_keep = veclen;
278
279 return 0;
280 }
281
nghttp2_bufs_wrap_free(nghttp2_bufs * bufs)282 void nghttp2_bufs_wrap_free(nghttp2_bufs *bufs)
283 {
284 if (bufs == NULL) {
285 return;
286 }
287
288 if (bufs->head) {
289 nghttp2_mem_free(bufs->mem, bufs->head);
290 }
291 }
292
nghttp2_bufs_seek_last_present(nghttp2_bufs * bufs)293 void nghttp2_bufs_seek_last_present(nghttp2_bufs *bufs)
294 {
295 nghttp2_buf_chain *ci;
296
297 for (ci = bufs->cur; ci; ci = ci->next) {
298 if (nghttp2_buf_len(&ci->buf) == 0) {
299 return;
300 } else {
301 bufs->cur = ci;
302 }
303 }
304 }
305
nghttp2_bufs_len(nghttp2_bufs * bufs)306 size_t nghttp2_bufs_len(nghttp2_bufs *bufs)
307 {
308 nghttp2_buf_chain *ci;
309 size_t len;
310
311 len = 0;
312 for (ci = bufs->head; ci; ci = ci->next) {
313 len += nghttp2_buf_len(&ci->buf);
314 }
315
316 return len;
317 }
318
bufs_alloc_chain(nghttp2_bufs * bufs)319 static int bufs_alloc_chain(nghttp2_bufs *bufs)
320 {
321 int rv;
322 nghttp2_buf_chain *chain;
323
324 if (bufs->cur->next) {
325 bufs->cur = bufs->cur->next;
326
327 return 0;
328 }
329
330 if (bufs->max_chunk == bufs->chunk_used) {
331 return NGHTTP2_ERR_BUFFER_ERROR;
332 }
333
334 rv = buf_chain_new(&chain, bufs->chunk_length, bufs->mem);
335 if (rv != 0) {
336 return rv;
337 }
338
339 DEBUGF("new buffer %zu bytes allocated for bufs %p, used %zu\n",
340 bufs->chunk_length, bufs, bufs->chunk_used);
341
342 ++bufs->chunk_used;
343
344 bufs->cur->next = chain;
345 bufs->cur = chain;
346
347 nghttp2_buf_shift_right(&bufs->cur->buf, bufs->offset);
348
349 return 0;
350 }
351
nghttp2_bufs_add(nghttp2_bufs * bufs,const void * data,size_t len)352 int nghttp2_bufs_add(nghttp2_bufs *bufs, const void *data, size_t len)
353 {
354 int rv;
355 size_t nwrite;
356 nghttp2_buf *buf;
357 const uint8_t *p;
358
359 p = data;
360
361 while (len) {
362 buf = &bufs->cur->buf;
363
364 nwrite = nghttp2_min(nghttp2_buf_avail(buf), len);
365 if (nwrite == 0) {
366 rv = bufs_alloc_chain(bufs);
367 if (rv != 0) {
368 return rv;
369 }
370 continue;
371 }
372
373 buf->last = nghttp2_cpymem(buf->last, p, nwrite);
374 p += nwrite;
375 len -= nwrite;
376 }
377
378 return 0;
379 }
380
bufs_ensure_addb(nghttp2_bufs * bufs)381 static int bufs_ensure_addb(nghttp2_bufs *bufs)
382 {
383 int rv;
384 nghttp2_buf *buf;
385
386 buf = &bufs->cur->buf;
387
388 if (nghttp2_buf_avail(buf) > 0) {
389 return 0;
390 }
391
392 rv = bufs_alloc_chain(bufs);
393 if (rv != 0) {
394 return rv;
395 }
396
397 return 0;
398 }
399
nghttp2_bufs_addb(nghttp2_bufs * bufs,uint8_t b)400 int nghttp2_bufs_addb(nghttp2_bufs *bufs, uint8_t b)
401 {
402 int rv;
403
404 rv = bufs_ensure_addb(bufs);
405 if (rv != 0) {
406 return rv;
407 }
408
409 *bufs->cur->buf.last++ = b;
410
411 return 0;
412 }
413
nghttp2_bufs_addb_hold(nghttp2_bufs * bufs,uint8_t b)414 int nghttp2_bufs_addb_hold(nghttp2_bufs *bufs, uint8_t b)
415 {
416 int rv;
417
418 rv = bufs_ensure_addb(bufs);
419 if (rv != 0) {
420 return rv;
421 }
422
423 *bufs->cur->buf.last = b;
424
425 return 0;
426 }
427
nghttp2_bufs_orb(nghttp2_bufs * bufs,uint8_t b)428 int nghttp2_bufs_orb(nghttp2_bufs *bufs, uint8_t b)
429 {
430 int rv;
431
432 rv = bufs_ensure_addb(bufs);
433 if (rv != 0) {
434 return rv;
435 }
436
437 *bufs->cur->buf.last++ |= b;
438
439 return 0;
440 }
441
nghttp2_bufs_orb_hold(nghttp2_bufs * bufs,uint8_t b)442 int nghttp2_bufs_orb_hold(nghttp2_bufs *bufs, uint8_t b)
443 {
444 int rv;
445
446 rv = bufs_ensure_addb(bufs);
447 if (rv != 0) {
448 return rv;
449 }
450
451 *bufs->cur->buf.last |= b;
452
453 return 0;
454 }
455
nghttp2_bufs_remove(nghttp2_bufs * bufs,uint8_t ** out)456 ssize_t nghttp2_bufs_remove(nghttp2_bufs *bufs, uint8_t **out)
457 {
458 size_t len;
459 nghttp2_buf_chain *chain;
460 nghttp2_buf *buf;
461 uint8_t *res;
462 nghttp2_buf resbuf;
463
464 len = 0;
465
466 for (chain = bufs->head; chain; chain = chain->next) {
467 len += nghttp2_buf_len(&chain->buf);
468 }
469
470 if (len == 0) {
471 res = NULL;
472 return 0;
473 }
474
475 res = nghttp2_mem_malloc(bufs->mem, len);
476 if (res == NULL) {
477 return NGHTTP2_ERR_NOMEM;
478 }
479
480 nghttp2_buf_wrap_init(&resbuf, res, len);
481
482 for (chain = bufs->head; chain; chain = chain->next) {
483 buf = &chain->buf;
484 resbuf.last =
485 nghttp2_cpymem(resbuf.last, buf->pos, nghttp2_buf_len(buf));
486 }
487
488 *out = res;
489
490 return (ssize_t)len;
491 }
492
nghttp2_bufs_remove_copy(nghttp2_bufs * bufs,uint8_t * out)493 size_t nghttp2_bufs_remove_copy(nghttp2_bufs *bufs, uint8_t *out)
494 {
495 size_t len;
496 nghttp2_buf_chain *chain;
497 nghttp2_buf *buf;
498 nghttp2_buf resbuf;
499
500 len = nghttp2_bufs_len(bufs);
501
502 nghttp2_buf_wrap_init(&resbuf, out, len);
503
504 for (chain = bufs->head; chain; chain = chain->next) {
505 buf = &chain->buf;
506 resbuf.last =
507 nghttp2_cpymem(resbuf.last, buf->pos, nghttp2_buf_len(buf));
508 }
509
510 return len;
511 }
512
nghttp2_bufs_reset(nghttp2_bufs * bufs)513 void nghttp2_bufs_reset(nghttp2_bufs *bufs)
514 {
515 nghttp2_buf_chain *chain, *ci;
516 size_t k;
517
518 k = bufs->chunk_keep;
519
520 for (ci = bufs->head; ci; ci = ci->next) {
521 nghttp2_buf_reset(&ci->buf);
522 nghttp2_buf_shift_right(&ci->buf, bufs->offset);
523
524 if (--k == 0) {
525 break;
526 }
527 }
528
529 if (ci) {
530 chain = ci->next;
531 ci->next = NULL;
532
533 for (ci = chain; ci;) {
534 chain = ci->next;
535
536 buf_chain_del(ci, bufs->mem);
537
538 ci = chain;
539 }
540
541 bufs->chunk_used = bufs->chunk_keep;
542 }
543
544 bufs->cur = bufs->head;
545 }
546
nghttp2_bufs_advance(nghttp2_bufs * bufs)547 int nghttp2_bufs_advance(nghttp2_bufs *bufs)
548 {
549 return bufs_alloc_chain(bufs);
550 }
551
nghttp2_bufs_next_present(nghttp2_bufs * bufs)552 int nghttp2_bufs_next_present(nghttp2_bufs *bufs)
553 {
554 nghttp2_buf_chain *chain;
555
556 chain = bufs->cur->next;
557
558 return chain && nghttp2_buf_len(&chain->buf);
559 }
560