1// Copyright (c) 2012 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#ifndef NET_BASE_UPLOAD_DATA_STREAM_H_
6#define NET_BASE_UPLOAD_DATA_STREAM_H_
7
8#include "base/gtest_prod_util.h"
9#include "base/memory/ref_counted.h"
10#include "base/memory/scoped_vector.h"
11#include "base/memory/weak_ptr.h"
12#include "net/base/completion_callback.h"
13#include "net/base/net_export.h"
14
15namespace net {
16
17class DrainableIOBuffer;
18class IOBuffer;
19class UploadElementReader;
20
21// A class to read all elements from an UploadData object.
22class NET_EXPORT UploadDataStream {
23 public:
24  // An enum used to construct chunked data stream.
25  enum Chunked { CHUNKED };
26
27  // Constructs a non-chunked data stream.
28  UploadDataStream(ScopedVector<UploadElementReader> element_readers,
29                   int64 identifier);
30
31  // Constructs a chunked data stream.
32  UploadDataStream(Chunked chunked, int64 identifier);
33
34  ~UploadDataStream();
35
36  // Creates UploadDataStream with a reader.
37  static UploadDataStream* CreateWithReader(
38      scoped_ptr<UploadElementReader> reader,
39      int64 identifier);
40
41  // Initializes the stream. This function must be called before calling any
42  // other method. It is not valid to call any method (other than the
43  // destructor) if Init() returns a failure. This method can be called multiple
44  // times. Calling this method after a Init() success results in resetting the
45  // state.
46  //
47  // Does the initialization synchronously and returns the result if possible,
48  // otherwise returns ERR_IO_PENDING and runs the callback with the result.
49  //
50  // Returns OK on success. Returns ERR_UPLOAD_FILE_CHANGED if the expected
51  // file modification time is set (usually not set, but set for sliced
52  // files) and the target file is changed.
53  int Init(const CompletionCallback& callback);
54
55  // When possible, reads up to |buf_len| bytes synchronously from the upload
56  // data stream to |buf| and returns the number of bytes read; otherwise,
57  // returns ERR_IO_PENDING and calls |callback| with the number of bytes read.
58  // Partial reads are allowed. Zero is returned on a call to Read when there
59  // are no remaining bytes in the stream, and IsEof() will return true
60  // hereafter.
61  //
62  // If there's less data to read than we initially observed (i.e. the actual
63  // upload data is smaller than size()), zeros are padded to ensure that
64  // size() bytes can be read, which can happen for TYPE_FILE payloads.
65  int Read(IOBuffer* buf, int buf_len, const CompletionCallback& callback);
66
67  // Identifies a particular upload instance, which is used by the cache to
68  // formulate a cache key.  This value should be unique across browser
69  // sessions.  A value of 0 is used to indicate an unspecified identifier.
70  int64 identifier() const { return identifier_; }
71
72  // Returns the total size of the data stream and the current position.
73  // size() is not to be used to determine whether the stream has ended
74  // because it is possible for the stream to end before its size is reached,
75  // for example, if the file is truncated. When the data is chunked, size()
76  // always returns zero.
77  uint64 size() const { return total_size_; }
78  uint64 position() const { return current_position_; }
79
80  bool is_chunked() const { return is_chunked_; }
81  bool last_chunk_appended() const { return last_chunk_appended_; }
82
83  const ScopedVector<UploadElementReader>& element_readers() const {
84    return element_readers_;
85  }
86
87  // Returns true if all data has been consumed from this upload data
88  // stream.
89  bool IsEOF() const;
90
91  // Returns true if the upload data in the stream is entirely in memory.
92  bool IsInMemory() const;
93
94  // Adds the given chunk of bytes to be sent with chunked transfer encoding.
95  void AppendChunk(const char* bytes, int bytes_len, bool is_last_chunk);
96
97  // Resets this instance to the uninitialized state.
98  void Reset();
99
100 private:
101  // Runs Init() for all element readers.
102  // This method is used to implement Init().
103  int InitInternal(int start_index, const CompletionCallback& callback);
104
105  // Resumes initialization and runs callback with the result when necessary.
106  void ResumePendingInit(int start_index,
107                         const CompletionCallback& callback,
108                         int previous_result);
109
110  // Reads data from the element readers.
111  // This method is used to implement Read().
112  int ReadInternal(scoped_refptr<DrainableIOBuffer> buf,
113                   const CompletionCallback& callback);
114
115  // Resumes pending read and calls callback with the result when necessary.
116  void ResumePendingRead(scoped_refptr<DrainableIOBuffer> buf,
117                         const CompletionCallback& callback,
118                         int previous_result);
119
120  // Processes result of UploadElementReader::Read(). If |result| indicates
121  // success, updates |buf|'s offset. Otherwise, sets |read_failed_| to true.
122  void ProcessReadResult(scoped_refptr<DrainableIOBuffer> buf,
123                         int result);
124
125  ScopedVector<UploadElementReader> element_readers_;
126
127  // Index of the current upload element (i.e. the element currently being
128  // read). The index is used as a cursor to iterate over elements in
129  // |upload_data_|.
130  size_t element_index_;
131
132  // Size and current read position within the upload data stream.
133  // |total_size_| is set to zero when the data is chunked.
134  uint64 total_size_;
135  uint64 current_position_;
136
137  const int64 identifier_;
138
139  const bool is_chunked_;
140  bool last_chunk_appended_;
141
142  // True if an error occcured during read operation.
143  bool read_failed_;
144
145  // True if the initialization was successful.
146  bool initialized_successfully_;
147
148  // Callback to resume reading chunked data.
149  base::Closure pending_chunked_read_callback_;
150
151  base::WeakPtrFactory<UploadDataStream> weak_ptr_factory_;
152
153  DISALLOW_COPY_AND_ASSIGN(UploadDataStream);
154};
155
156}  // namespace net
157
158#endif  // NET_BASE_UPLOAD_DATA_STREAM_H_
159