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
22namespace dap {
23
24////////////////////////////////////////////////////////////////////////////////
25// ContentReader
26////////////////////////////////////////////////////////////////////////////////
27ContentReader::ContentReader(const std::shared_ptr<Reader>& reader)
28 : reader(reader) {}
29
30ContentReader& ContentReader::operator=(ContentReader&& rhs) noexcept {
31 buf = std::move(rhs.buf);
32 reader = std::move(rhs.reader);
33 return *this;
34}
35
36bool ContentReader::isOpen() {
37 return reader ? reader->isOpen() : false;
38}
39
40void ContentReader::close() {
41 if (reader) {
42 reader->close();
43 }
44}
45
46std::string ContentReader::read() {
47 matched_idx = 0;
48
49 // Find Content-Length header prefix
50 if (!scan("Content-Length:")) {
51 return "";
52 }
53
54 // Skip whitespace and tabs
55 while (matchAny(" \t")) {
56 }
57
58 // Parse length
59 size_t len = 0;
60 while (true) {
61 auto c = matchAny("0123456789");
62 if (c == 0) {
63 break;
64 }
65 len *= 10;
66 len += size_t(c) - size_t('0');
67 }
68 if (len == 0) {
69 return "";
70 }
71 // Expect \r\n\r\n
72 if (!match("\r\n\r\n")) {
73 return "";
74 }
75
76 // Read message
77 if (!buffer(len + matched_idx)) {
78 return "";
79 }
80
81 for (size_t i = 0; i < matched_idx; i++) {
82 buf.pop_front();
83 }
84
85 std::string out;
86 out.reserve(len);
87 for (size_t i = 0; i < len; i++) {
88 out.push_back(static_cast<char>(buf.front()));
89 buf.pop_front();
90 }
91 return out;
92}
93
94bool ContentReader::scan(const uint8_t* seq, size_t len) {
95 while (buffer(len)) {
96 if (match(seq, len)) {
97 return true;
98 }
99 buf.pop_front();
100 }
101 return false;
102}
103
104bool ContentReader::scan(const char* str) {
105 auto len = strlen(str);
106 return scan(reinterpret_cast<const uint8_t*>(str), len);
107}
108
109bool ContentReader::match(const uint8_t* seq, size_t len) {
110 if (!buffer(len + matched_idx)) {
111 return false;
112 }
113 auto it = matched_idx;
114 for (size_t i = 0; i < len; i++, it++) {
115 if (buf[it] != seq[i]) {
116 return false;
117 }
118 }
119
120 matched_idx += len;
121 return true;
122}
123
124bool ContentReader::match(const char* str) {
125 auto len = strlen(str);
126 return match(reinterpret_cast<const uint8_t*>(str), len);
127}
128
129char ContentReader::matchAny(const char* chars) {
130 if (!buffer(1 + matched_idx)) {
131 return false;
132 }
133 int c = buf[matched_idx];
134 if (auto p = strchr(chars, c)) {
135 matched_idx++;
136 return *p;
137 }
138 return 0;
139}
140
141bool ContentReader::buffer(size_t bytes) {
142 if (bytes < buf.size()) {
143 return true;
144 }
145 bytes -= buf.size();
146 while (bytes > 0) {
147 uint8_t chunk[256];
148 auto numWant = std::min(sizeof(chunk), bytes);
149 auto numGot = reader->read(chunk, numWant);
150 if (numGot == 0) {
151 return false;
152 }
153 for (size_t i = 0; i < numGot; i++) {
154 buf.push_back(chunk[i]);
155 }
156 bytes -= numGot;
157 }
158 return true;
159}
160
161////////////////////////////////////////////////////////////////////////////////
162// ContentWriter
163////////////////////////////////////////////////////////////////////////////////
164ContentWriter::ContentWriter(const std::shared_ptr<Writer>& rhs)
165 : writer(rhs) {}
166
167ContentWriter& ContentWriter::operator=(ContentWriter&& rhs) noexcept {
168 writer = std::move(rhs.writer);
169 return *this;
170}
171
172bool ContentWriter::isOpen() {
173 return writer ? writer->isOpen() : false;
174}
175
176void ContentWriter::close() {
177 if (writer) {
178 writer->close();
179 }
180}
181
182bool ContentWriter::write(const std::string& msg) const {
183 auto header =
184 std::string("Content-Length: ") + std::to_string(msg.size()) + "\r\n\r\n";
185 return writer->write(header.data(), header.size()) &&
186 writer->write(msg.data(), msg.size());
187}
188
189} // namespace dap
190