blob: ec772f0f3254c72ca11cf8ac9060f9f2abf57e0d [file] [log] [blame]
James Kuszmaul82f6c042021-01-17 11:30:16 -08001/**
2 * @file http/chunk.c Chunked Transfer Encoding
3 *
4 * Copyright (C) 2011 Creytiv.com
5 */
6
7#include <re_types.h>
8#include <re_mem.h>
9#include <re_mbuf.h>
10#include "http.h"
11
12
13static int decode_chunk_size(struct http_chunk *chunk, struct mbuf *mb)
14{
15 while (mbuf_get_left(mb)) {
16
17 char ch = (char)mbuf_read_u8(mb);
18 uint8_t c;
19
20 if (ch == '\n') {
21 if (chunk->digit) {
22 chunk->digit = false;
23 chunk->param = false;
24
25 return 0;
26 }
27 else
28 continue;
29 }
30
31 if (chunk->param)
32 continue;
33
34 if ('0' <= ch && ch <= '9')
35 c = ch - '0';
36 else if ('A' <= ch && ch <= 'F')
37 c = ch - 'A' + 10;
38 else if ('a' <= ch && ch <= 'f')
39 c = ch - 'a' + 10;
40 else if (ch == '\r' || ch == ' ' || ch == '\t')
41 continue;
42 else if (ch == ';' && chunk->digit) {
43 chunk->param = true;
44 continue;
45 }
46 else
47 return EPROTO;
48
49 chunk->digit = true;
50
51 chunk->size <<= 4;
52 chunk->size += c;
53 }
54
55 return ENODATA;
56}
57
58
59static int decode_trailer(struct http_chunk *chunk, struct mbuf *mb)
60{
61 while (mbuf_get_left(mb)) {
62
63 char ch = (char)mbuf_read_u8(mb);
64
65 if (ch == '\n') {
66 if (++chunk->lf >= 2)
67 return 0;
68 }
69 else if (ch != '\r')
70 chunk->lf = 0;
71 }
72
73 return ENODATA;
74}
75
76
77int http_chunk_decode(struct http_chunk *chunk, struct mbuf *mb, size_t *size)
78{
79 int err;
80
81 if (!chunk || !mb || !size)
82 return EINVAL;
83
84 if (chunk->trailer) {
85 err = decode_trailer(chunk, mb);
86 if (err)
87 return err;
88
89 *size = 0;
90
91 return 0;
92 }
93
94 err = decode_chunk_size(chunk, mb);
95 if (err)
96 return err;
97
98 if (chunk->size == 0) {
99 chunk->trailer = true;
100 chunk->lf = 1;
101
102 err = decode_trailer(chunk, mb);
103 if (err)
104 return err;
105 }
106
107 *size = chunk->size;
108 chunk->size = 0;
109
110 return 0;
111}