Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Kitware
GitHub Repository: Kitware/CMake
Path: blob/master/Utilities/cmcppdap/src/content_stream.cpp
3153 views
1
// Copyright 2019 Google LLC
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
// https://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
15
#include "content_stream.h"
16
17
#include "dap/io.h"
18
19
#include <string.h> // strlen
20
#include <algorithm> // std::min
21
22
namespace dap {
23
24
////////////////////////////////////////////////////////////////////////////////
25
// ContentReader
26
////////////////////////////////////////////////////////////////////////////////
27
ContentReader::ContentReader(
28
const std::shared_ptr<Reader>& reader,
29
OnInvalidData on_invalid_data /* = OnInvalidData::kIgnore */)
30
: reader(reader), on_invalid_data(on_invalid_data) {}
31
32
ContentReader& ContentReader::operator=(ContentReader&& rhs) noexcept {
33
buf = std::move(rhs.buf);
34
reader = std::move(rhs.reader);
35
on_invalid_data = std::move(rhs.on_invalid_data);
36
return *this;
37
}
38
39
bool ContentReader::isOpen() {
40
return reader ? reader->isOpen() : false;
41
}
42
43
void ContentReader::close() {
44
if (reader) {
45
reader->close();
46
}
47
}
48
49
std::string ContentReader::read() {
50
// Find Content-Length header prefix
51
if (on_invalid_data == kClose) {
52
if (!match("Content-Length:")) {
53
return badHeader();
54
}
55
} else {
56
if (!scan("Content-Length:")) {
57
return "";
58
}
59
}
60
// Skip whitespace and tabs
61
while (matchAny(" \t")) {
62
}
63
// Parse length
64
size_t len = 0;
65
while (true) {
66
auto c = matchAny("0123456789");
67
if (c == 0) {
68
break;
69
}
70
len *= 10;
71
len += size_t(c) - size_t('0');
72
}
73
if (len == 0) {
74
return "";
75
}
76
77
// Expect \r\n\r\n
78
if (!match("\r\n\r\n")) {
79
return badHeader();
80
}
81
82
// Read message
83
if (!buffer(len)) {
84
return "";
85
}
86
std::string out;
87
out.reserve(len);
88
for (size_t i = 0; i < len; i++) {
89
out.push_back(static_cast<char>(buf.front()));
90
buf.pop_front();
91
}
92
return out;
93
}
94
95
bool ContentReader::scan(const uint8_t* seq, size_t len) {
96
while (buffer(len)) {
97
if (match(seq, len)) {
98
return true;
99
}
100
buf.pop_front();
101
}
102
return false;
103
}
104
105
bool ContentReader::scan(const char* str) {
106
auto len = strlen(str);
107
return scan(reinterpret_cast<const uint8_t*>(str), len);
108
}
109
110
bool ContentReader::match(const uint8_t* seq, size_t len) {
111
if (!buffer(len)) {
112
return false;
113
}
114
auto it = buf.begin();
115
for (size_t i = 0; i < len; i++, it++) {
116
if (*it != seq[i]) {
117
return false;
118
}
119
}
120
for (size_t i = 0; i < len; i++) {
121
buf.pop_front();
122
}
123
return true;
124
}
125
126
bool ContentReader::match(const char* str) {
127
auto len = strlen(str);
128
return match(reinterpret_cast<const uint8_t*>(str), len);
129
}
130
131
char ContentReader::matchAny(const char* chars) {
132
if (!buffer(1)) {
133
return false;
134
}
135
int c = buf.front();
136
if (auto p = strchr(chars, c)) {
137
buf.pop_front();
138
return *p;
139
}
140
return 0;
141
}
142
143
bool ContentReader::buffer(size_t bytes) {
144
if (bytes < buf.size()) {
145
return true;
146
}
147
bytes -= buf.size();
148
while (bytes > 0) {
149
uint8_t chunk[256];
150
auto numWant = std::min(sizeof(chunk), bytes);
151
auto numGot = reader->read(chunk, numWant);
152
if (numGot == 0) {
153
return false;
154
}
155
for (size_t i = 0; i < numGot; i++) {
156
buf.push_back(chunk[i]);
157
}
158
bytes -= numGot;
159
}
160
return true;
161
}
162
163
std::string ContentReader::badHeader() {
164
if (on_invalid_data == kClose) {
165
close();
166
}
167
return "";
168
}
169
170
////////////////////////////////////////////////////////////////////////////////
171
// ContentWriter
172
////////////////////////////////////////////////////////////////////////////////
173
ContentWriter::ContentWriter(const std::shared_ptr<Writer>& rhs)
174
: writer(rhs) {}
175
176
ContentWriter& ContentWriter::operator=(ContentWriter&& rhs) noexcept {
177
writer = std::move(rhs.writer);
178
return *this;
179
}
180
181
bool ContentWriter::isOpen() {
182
return writer ? writer->isOpen() : false;
183
}
184
185
void ContentWriter::close() {
186
if (writer) {
187
writer->close();
188
}
189
}
190
191
bool ContentWriter::write(const std::string& msg) const {
192
auto header =
193
std::string("Content-Length: ") + std::to_string(msg.size()) + "\r\n\r\n";
194
return writer->write(header.data(), header.size()) &&
195
writer->write(msg.data(), msg.size());
196
}
197
198
} // namespace dap
199
200