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