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