1 // Copyright (c) 2018 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "quiche/quic/core/http/quic_spdy_stream_body_manager.h"
6
7 #include <algorithm>
8
9 #include "absl/strings/string_view.h"
10 #include "quiche/quic/platform/api/quic_logging.h"
11
12 namespace quic {
13
QuicSpdyStreamBodyManager()14 QuicSpdyStreamBodyManager::QuicSpdyStreamBodyManager()
15 : total_body_bytes_received_(0) {}
16
OnNonBody(QuicByteCount length)17 size_t QuicSpdyStreamBodyManager::OnNonBody(QuicByteCount length) {
18 QUICHE_DCHECK_NE(0u, length);
19
20 if (fragments_.empty()) {
21 // Non-body bytes can be consumed immediately, because all previously
22 // received body bytes have been read.
23 return length;
24 }
25
26 // Non-body bytes will be consumed after last body fragment is read.
27 fragments_.back().trailing_non_body_byte_count += length;
28 return 0;
29 }
30
OnBody(absl::string_view body)31 void QuicSpdyStreamBodyManager::OnBody(absl::string_view body) {
32 QUICHE_DCHECK(!body.empty());
33
34 fragments_.push_back({body, 0});
35 total_body_bytes_received_ += body.length();
36 }
37
OnBodyConsumed(size_t num_bytes)38 size_t QuicSpdyStreamBodyManager::OnBodyConsumed(size_t num_bytes) {
39 QuicByteCount bytes_to_consume = 0;
40 size_t remaining_bytes = num_bytes;
41
42 while (remaining_bytes > 0) {
43 if (fragments_.empty()) {
44 QUIC_BUG(quic_bug_10394_1) << "Not enough available body to consume.";
45 return 0;
46 }
47
48 Fragment& fragment = fragments_.front();
49 const absl::string_view body = fragment.body;
50
51 if (body.length() > remaining_bytes) {
52 // Consume leading |remaining_bytes| bytes of body.
53 bytes_to_consume += remaining_bytes;
54 fragment.body = body.substr(remaining_bytes);
55 return bytes_to_consume;
56 }
57
58 // Consume entire fragment and the following
59 // |trailing_non_body_byte_count| bytes.
60 remaining_bytes -= body.length();
61 bytes_to_consume += body.length() + fragment.trailing_non_body_byte_count;
62 fragments_.pop_front();
63 }
64
65 return bytes_to_consume;
66 }
67
PeekBody(iovec * iov,size_t iov_len) const68 int QuicSpdyStreamBodyManager::PeekBody(iovec* iov, size_t iov_len) const {
69 QUICHE_DCHECK(iov);
70 QUICHE_DCHECK_GT(iov_len, 0u);
71
72 // TODO(bnc): Is this really necessary?
73 if (fragments_.empty()) {
74 iov[0].iov_base = nullptr;
75 iov[0].iov_len = 0;
76 return 0;
77 }
78
79 size_t iov_filled = 0;
80 while (iov_filled < fragments_.size() && iov_filled < iov_len) {
81 absl::string_view body = fragments_[iov_filled].body;
82 iov[iov_filled].iov_base = const_cast<char*>(body.data());
83 iov[iov_filled].iov_len = body.size();
84 iov_filled++;
85 }
86
87 return iov_filled;
88 }
89
ReadableBytes() const90 size_t QuicSpdyStreamBodyManager::ReadableBytes() const {
91 size_t count = 0;
92 for (auto const& fragment : fragments_) {
93 count += fragment.body.length();
94 }
95 return count;
96 }
97
ReadBody(const struct iovec * iov,size_t iov_len,size_t * total_bytes_read)98 size_t QuicSpdyStreamBodyManager::ReadBody(const struct iovec* iov,
99 size_t iov_len,
100 size_t* total_bytes_read) {
101 *total_bytes_read = 0;
102 QuicByteCount bytes_to_consume = 0;
103
104 // The index of iovec to write to.
105 size_t index = 0;
106 // Address to write to within current iovec.
107 char* dest = reinterpret_cast<char*>(iov[index].iov_base);
108 // Remaining space in current iovec.
109 size_t dest_remaining = iov[index].iov_len;
110
111 while (!fragments_.empty()) {
112 Fragment& fragment = fragments_.front();
113 const absl::string_view body = fragment.body;
114
115 const size_t bytes_to_copy =
116 std::min<size_t>(body.length(), dest_remaining);
117
118 // According to Section 7.1.4 of the C11 standard (ISO/IEC 9899:2011), null
119 // pointers should not be passed to standard library functions.
120 if (bytes_to_copy > 0) {
121 memcpy(dest, body.data(), bytes_to_copy);
122 }
123
124 bytes_to_consume += bytes_to_copy;
125 *total_bytes_read += bytes_to_copy;
126
127 if (bytes_to_copy == body.length()) {
128 // Entire fragment read.
129 bytes_to_consume += fragment.trailing_non_body_byte_count;
130 fragments_.pop_front();
131 } else {
132 // Consume leading |bytes_to_copy| bytes of body.
133 fragment.body = body.substr(bytes_to_copy);
134 }
135
136 if (bytes_to_copy == dest_remaining) {
137 // Current iovec full.
138 ++index;
139 if (index == iov_len) {
140 break;
141 }
142 dest = reinterpret_cast<char*>(iov[index].iov_base);
143 dest_remaining = iov[index].iov_len;
144 } else {
145 // Advance destination parameters within this iovec.
146 dest += bytes_to_copy;
147 dest_remaining -= bytes_to_copy;
148 }
149 }
150
151 return bytes_to_consume;
152 }
153
154 } // namespace quic
155