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 "net/third_party/quiche/src/quic/core/http/quic_spdy_stream_body_manager.h"
6
7 #include <algorithm>
8
9 #include "absl/strings/string_view.h"
10 #include "net/third_party/quiche/src/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 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 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 << "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 DCHECK(iov);
70 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
ReadBody(const struct iovec * iov,size_t iov_len,size_t * total_bytes_read)90 size_t QuicSpdyStreamBodyManager::ReadBody(const struct iovec* iov,
91 size_t iov_len,
92 size_t* total_bytes_read) {
93 *total_bytes_read = 0;
94 QuicByteCount bytes_to_consume = 0;
95
96 // The index of iovec to write to.
97 size_t index = 0;
98 // Address to write to within current iovec.
99 char* dest = reinterpret_cast<char*>(iov[index].iov_base);
100 // Remaining space in current iovec.
101 size_t dest_remaining = iov[index].iov_len;
102
103 while (!fragments_.empty()) {
104 Fragment& fragment = fragments_.front();
105 const absl::string_view body = fragment.body;
106
107 const size_t bytes_to_copy =
108 std::min<size_t>(body.length(), dest_remaining);
109 memcpy(dest, body.data(), bytes_to_copy);
110 bytes_to_consume += bytes_to_copy;
111 *total_bytes_read += bytes_to_copy;
112
113 if (bytes_to_copy == body.length()) {
114 // Entire fragment read.
115 bytes_to_consume += fragment.trailing_non_body_byte_count;
116 fragments_.pop_front();
117 } else {
118 // Consume leading |bytes_to_copy| bytes of body.
119 fragment.body = body.substr(bytes_to_copy);
120 }
121
122 if (bytes_to_copy == dest_remaining) {
123 // Current iovec full.
124 ++index;
125 if (index == iov_len) {
126 break;
127 }
128 dest = reinterpret_cast<char*>(iov[index].iov_base);
129 dest_remaining = iov[index].iov_len;
130 } else {
131 // Advance destination parameters within this iovec.
132 dest += bytes_to_copy;
133 dest_remaining -= bytes_to_copy;
134 }
135 }
136
137 return bytes_to_consume;
138 }
139
140 } // namespace quic
141