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