xref: /aosp_15_r20/external/cronet/net/third_party/quiche/src/quiche/quic/core/http/quic_spdy_stream_body_manager.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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