OpenVPN 3 Core Library
Loading...
Searching...
No Matches
chunked.hpp
Go to the documentation of this file.
1// OpenVPN -- An application to securely tunnel IP networks
2// over a single port, with support for SSL/TLS-based
3// session authentication and key exchange,
4// packet encryption, packet authentication, and
5// packet compression.
6//
7// Copyright (C) 2012- OpenVPN Inc.
8//
9// SPDX-License-Identifier: MPL-2.0 OR AGPL-3.0-only WITH openvpn3-openssl-exception
10//
11
12#pragma once
13
18
19namespace openvpn::WS {
21{
34
35 public:
37 : state(hex),
38 size(0)
39 {
40 }
41
42 template <typename PARENT>
43 bool receive(PARENT &callback, BufferAllocated &buf)
44 {
45 while (buf.defined())
46 {
47 if (state == chunk)
48 {
49 if (size)
50 {
51 if (buf.size() <= size)
52 {
53 size -= buf.size();
54 callback.chunked_content_in(buf);
55 break;
56 }
57 else
58 {
59 BufferAllocated content(buf.read_alloc(size), size, 0);
60 size = 0;
61 callback.chunked_content_in(content);
62 }
63 }
64 else
66 }
67 else if (state == done)
68 break;
69 else
70 {
71 const char c = char(buf.pop_front());
72 reprocess:
73 switch (state)
74 {
75 case hex:
76 {
77 const int v = parse_hex_char(c);
78 if (v >= 0)
79 size = (size << 4) + v;
80 else
81 {
83 goto reprocess;
84 }
85 }
86 break;
87 case post_hex:
88 if (c == '\r')
90 break;
91 case post_hex_lf:
92 if (c == '\n')
93 {
94 if (size)
95 state = chunk;
96 else
98 }
99 else
100 {
101 state = post_hex;
102 goto reprocess;
103 }
104 break;
105 case post_chunk_cr:
106 if (c == '\r')
108 break;
109 case post_chunk_lf:
110 if (c == '\n')
111 state = hex;
112 else
113 {
115 goto reprocess;
116 }
117 break;
118 case post_content_cr:
119 if (c == '\r')
121 break;
122 case post_content_lf:
123 if (c == '\n')
124 state = done;
125 else
126 {
128 goto reprocess;
129 }
130 break;
131 default: // should never be reached
132 break;
133 }
134 }
135 }
136 return state == done;
137 }
138
140 {
141 const size_t headroom = 24;
142 const size_t tailroom = 16;
143 static const char crlf[] = "\r\n";
144
145 if (!buf || buf->offset() < headroom || buf->remaining() < tailroom)
146 {
147 // insufficient headroom/tailroom, must realloc
148 Frame::Context fc(headroom, 0, tailroom, 0, sizeof(size_t), 0);
149 buf = fc.copy(buf);
150 }
151
152 size_t size = buf->size();
153 buf->prepend((unsigned char *)crlf, 2);
154 if (size)
155 {
156 while (size)
157 {
158 char *pc = (char *)buf->prepend_alloc(1);
159 *pc = render_hex_char(size & 0xF);
160 size >>= 4;
161 }
162 }
163 else
164 {
165 char *pc = (char *)buf->prepend_alloc(1);
166 *pc = '0';
167 }
168 buf->write((unsigned char *)crlf, 2);
169 return buf;
170 }
171
172 private:
174 size_t size;
175};
176} // namespace openvpn::WS
bool defined() const
Returns true if the buffer is not empty.
Definition buffer.hpp:1207
size_t size() const
Returns the size of the buffer in T objects.
Definition buffer.hpp:1225
auto * read_alloc(const size_t size)
Allocate memory and read data from the buffer into the allocated memory.
Definition buffer.hpp:1326
T pop_front()
Removes and returns the first element from the buffer.
Definition buffer.hpp:1239
BufferPtr copy(const unsigned char *data, const size_t size) const
Definition frame.hpp:138
static BufferPtr transmit(BufferPtr buf)
Definition chunked.hpp:139
bool receive(PARENT &callback, BufferAllocated &buf)
Definition chunked.hpp:43
int parse_hex_char(const int c)
Definition hexstr.hpp:65
char render_hex_char(const int c, const bool caps=false)
Definition hexstr.hpp:42