• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2014 The Chromium Authors
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/base/chunked_upload_data_stream.h"
6 
7 #include "base/check_op.h"
8 #include "base/memory/ptr_util.h"
9 #include "net/base/io_buffer.h"
10 #include "net/base/net_errors.h"
11 
12 namespace net {
13 
14 ChunkedUploadDataStream::Writer::~Writer() = default;
15 
AppendData(base::span<const uint8_t> data,bool is_done)16 bool ChunkedUploadDataStream::Writer::AppendData(base::span<const uint8_t> data,
17                                                  bool is_done) {
18   if (!upload_data_stream_)
19     return false;
20   upload_data_stream_->AppendData(data, is_done);
21   return true;
22 }
23 
Writer(base::WeakPtr<ChunkedUploadDataStream> upload_data_stream)24 ChunkedUploadDataStream::Writer::Writer(
25     base::WeakPtr<ChunkedUploadDataStream> upload_data_stream)
26     : upload_data_stream_(upload_data_stream) {}
27 
ChunkedUploadDataStream(int64_t identifier,bool has_null_source)28 ChunkedUploadDataStream::ChunkedUploadDataStream(int64_t identifier,
29                                                  bool has_null_source)
30     : UploadDataStream(/*is_chunked=*/true, has_null_source, identifier) {}
31 
32 ChunkedUploadDataStream::~ChunkedUploadDataStream() = default;
33 
34 std::unique_ptr<ChunkedUploadDataStream::Writer>
CreateWriter()35 ChunkedUploadDataStream::CreateWriter() {
36   return base::WrapUnique(new Writer(weak_factory_.GetWeakPtr()));
37 }
38 
AppendData(base::span<const uint8_t> data,bool is_done)39 void ChunkedUploadDataStream::AppendData(base::span<const uint8_t> data,
40                                          bool is_done) {
41   DCHECK(!all_data_appended_);
42   DCHECK(!data.empty() || is_done);
43   if (!data.empty()) {
44     upload_data_.push_back(
45         std::make_unique<std::vector<uint8_t>>(data.begin(), data.end()));
46   }
47   all_data_appended_ = is_done;
48 
49   if (!read_buffer_.get())
50     return;
51 
52   int result = ReadChunk(read_buffer_.get(), read_buffer_len_);
53   // Shouldn't get an error or ERR_IO_PENDING.
54   DCHECK_GE(result, 0);
55   read_buffer_ = nullptr;
56   read_buffer_len_ = 0;
57   OnReadCompleted(result);
58 }
59 
InitInternal(const NetLogWithSource & net_log)60 int ChunkedUploadDataStream::InitInternal(const NetLogWithSource& net_log) {
61   // ResetInternal should already have been called.
62   DCHECK(!read_buffer_.get());
63   DCHECK_EQ(0u, read_index_);
64   DCHECK_EQ(0u, read_offset_);
65   return OK;
66 }
67 
ReadInternal(IOBuffer * buf,int buf_len)68 int ChunkedUploadDataStream::ReadInternal(IOBuffer* buf, int buf_len) {
69   DCHECK_LT(0, buf_len);
70   DCHECK(!read_buffer_.get());
71 
72   int result = ReadChunk(buf, buf_len);
73   if (result == ERR_IO_PENDING) {
74     read_buffer_ = buf;
75     read_buffer_len_ = buf_len;
76   }
77   return result;
78 }
79 
ResetInternal()80 void ChunkedUploadDataStream::ResetInternal() {
81   read_buffer_ = nullptr;
82   read_buffer_len_ = 0;
83   read_index_ = 0;
84   read_offset_ = 0;
85 }
86 
ReadChunk(IOBuffer * buf,int buf_len)87 int ChunkedUploadDataStream::ReadChunk(IOBuffer* buf, int buf_len) {
88   // Copy as much data as possible from |upload_data_| to |buf|.
89   size_t bytes_read = 0;
90   const auto buf_len_s = base::checked_cast<size_t>(buf_len);
91   while (read_index_ < upload_data_.size() && bytes_read < buf_len_s) {
92     base::span<const uint8_t> data(*upload_data_[read_index_].get());
93     base::span<const uint8_t> bytes_to_read = data.subspan(
94         read_offset_,
95         std::min(buf_len_s - bytes_read, data.size() - read_offset_));
96     buf->span().subspan(bytes_read).copy_prefix_from(bytes_to_read);
97     bytes_read += bytes_to_read.size();
98     read_offset_ += bytes_to_read.size();
99     if (read_offset_ == data.size()) {
100       read_index_++;
101       read_offset_ = 0;
102     }
103   }
104   DCHECK_LE(bytes_read, buf_len_s);
105 
106   // If no data was written, and not all data has been appended, return
107   // ERR_IO_PENDING. The read will be completed in the next call to AppendData.
108   if (bytes_read == 0 && !all_data_appended_) {
109     return ERR_IO_PENDING;
110   }
111 
112   if (read_index_ == upload_data_.size() && all_data_appended_) {
113     SetIsFinalChunk();
114   }
115   return base::checked_cast<int>(bytes_read);
116 }
117 
118 }  // namespace net
119