summaryrefslogtreecommitdiff
path: root/chromium/net/base/upload_file_element_reader.h
blob: 197ef3132047a687a6f0ca565d4f5bcad91913c0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef NET_BASE_UPLOAD_FILE_ELEMENT_READER_H_
#define NET_BASE_UPLOAD_FILE_ELEMENT_READER_H_

#include <stdint.h>

#include <memory>

#include "base/compiler_specific.h"
#include "base/files/file.h"
#include "base/files/file_path.h"
#include "base/gtest_prod_util.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "base/time/time.h"
#include "net/base/net_export.h"
#include "net/base/upload_element_reader.h"

namespace base {
class TaskRunner;
}

namespace net {

class FileStream;

// An UploadElementReader implementation for file.
class NET_EXPORT UploadFileElementReader : public UploadElementReader {
 public:
  // |file| must be valid and opened for reading. On Windows, the file must have
  // been opened with File::FLAG_ASYNC, and elsewhere it must have ben opened
  // without it. |path| is never validated or used to re-open the file. It's
  // only used as the return value for path().
  // |task_runner| is used to perform file operations. It must not be NULL.
  //
  // TODO(mmenke): Remove |task_runner| argument, and use the ThreadPool
  // instead.
  UploadFileElementReader(base::TaskRunner* task_runner,
                          base::File file,
                          const base::FilePath& path,
                          uint64_t range_offset,
                          uint64_t range_length,
                          const base::Time& expected_modification_time);

  // Same a above, but takes a FilePath instead.
  // TODO(mmenke): Remove if all consumers can be switched to the first
  // constructor.
  UploadFileElementReader(base::TaskRunner* task_runner,
                          const base::FilePath& path,
                          uint64_t range_offset,
                          uint64_t range_length,
                          const base::Time& expected_modification_time);

  UploadFileElementReader(const UploadFileElementReader&) = delete;
  UploadFileElementReader& operator=(const UploadFileElementReader&) = delete;
  ~UploadFileElementReader() override;

  const base::FilePath& path() const { return path_; }
  uint64_t range_offset() const { return range_offset_; }
  uint64_t range_length() const { return range_length_; }
  const base::Time& expected_modification_time() const {
    return expected_modification_time_;
  }

  // UploadElementReader overrides:
  const UploadFileElementReader* AsFileReader() const override;
  int Init(CompletionOnceCallback callback) override;
  uint64_t GetContentLength() const override;
  uint64_t BytesRemaining() const override;
  int Read(IOBuffer* buf,
           int buf_length,
           CompletionOnceCallback callback) override;

 private:
  enum class State {
    // No async operation is pending.
    IDLE,

    // The ordered sequence of events started by calling Init().

    // Opens file. State is skipped if file already open.
    OPEN,
    OPEN_COMPLETE,
    SEEK,
    GET_FILE_INFO,
    GET_FILE_INFO_COMPLETE,

    // There is no READ state as reads are always started immediately on Read().
    READ_COMPLETE,
  };
  FRIEND_TEST_ALL_PREFIXES(ElementsUploadDataStreamTest, FileSmallerThanLength);
  FRIEND_TEST_ALL_PREFIXES(HttpNetworkTransactionTest,
                           UploadFileSmallerThanLength);

  int DoLoop(int result);

  int DoOpen();
  int DoOpenComplete(int result);
  int DoSeek();
  int DoGetFileInfo(int result);
  int DoGetFileInfoComplete(int result);
  int DoReadComplete(int result);

  void OnIOComplete(int result);

  // Sets an value to override the result for GetContentLength().
  // Used for tests.
  struct NET_EXPORT_PRIVATE ScopedOverridingContentLengthForTests {
    explicit ScopedOverridingContentLengthForTests(uint64_t value);
    ~ScopedOverridingContentLengthForTests();
  };

  scoped_refptr<base::TaskRunner> task_runner_;
  const base::FilePath path_;
  const uint64_t range_offset_;
  const uint64_t range_length_;
  const base::Time expected_modification_time_;
  std::unique_ptr<FileStream> file_stream_;
  uint64_t content_length_ = 0;
  uint64_t bytes_remaining_ = 0;

  // File information. Only valid during GET_FILE_INFO_COMPLETE state.
  base::File::Info file_info_;

  State next_state_ = State::IDLE;
  CompletionOnceCallback pending_callback_;
  // True if Init() was called while an async operation was in progress.
  bool init_called_while_operation_pending_ = false;

  base::WeakPtrFactory<UploadFileElementReader> weak_ptr_factory_{this};
};

}  // namespace net

#endif  // NET_BASE_UPLOAD_FILE_ELEMENT_READER_H_