summaryrefslogtreecommitdiff
path: root/chromium/net/http/partial_data.h
blob: 6586272f7ab5f2d926d99bcd9549bcae9c9f0364 (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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
// Copyright 2011 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_HTTP_PARTIAL_DATA_H_
#define NET_HTTP_PARTIAL_DATA_H_

#include <stdint.h>

#include "base/memory/weak_ptr.h"
#include "net/base/completion_once_callback.h"
#include "net/disk_cache/disk_cache.h"
#include "net/http/http_byte_range.h"
#include "net/http/http_request_headers.h"


namespace net {

class HttpResponseHeaders;
class IOBuffer;

// This class provides support for dealing with range requests and the
// subsequent partial-content responses. We use sparse cache entries to store
// these requests. This class is tightly integrated with HttpCache::Transaction
// and it is intended to allow a cleaner implementation of that class.
//
// In order to fulfill range requests, we may have to perform a sequence of
// reads from the cache, interleaved with reads from the network / writes to the
// cache. This class basically keeps track of the data required to perform each
// of those individual network / cache requests.
class PartialData {
 public:
  PartialData();

  PartialData(const PartialData&) = delete;
  PartialData& operator=(const PartialData&) = delete;

  ~PartialData();

  // Performs initialization of the object by examining the request |headers|
  // and verifying that we can process the requested range. Returns true if
  // we can process the requested range, and false otherwise.
  bool Init(const HttpRequestHeaders& headers);

  // Sets the headers that we should use to make byte range requests. This is a
  // subset of the request extra headers, with byte-range related headers
  // removed.
  void SetHeaders(const HttpRequestHeaders& headers);

  // Restores the byte-range headers, by appending the byte range to the headers
  // provided to SetHeaders().
  void RestoreHeaders(HttpRequestHeaders* headers) const;

  // Starts the checks to perform a cache validation. Returns 0 when there is no
  // need to perform more operations because we reached the end of the request
  // (so 0 bytes should be actually returned to the user), a positive number to
  // indicate that PrepareCacheValidation should be called, or an appropriate
  // error code. If this method returns ERR_IO_PENDING, the |callback| will be
  // notified when the result is ready.
  int ShouldValidateCache(disk_cache::Entry* entry,
                          CompletionOnceCallback callback);

  // Builds the required |headers| to perform the proper cache validation for
  // the next range to be fetched.
  void PrepareCacheValidation(disk_cache::Entry* entry,
                              HttpRequestHeaders* headers);

  // Returns true if the current range is stored in the cache.
  bool IsCurrentRangeCached() const;

  // Returns true if the current range is the last one needed to fulfill the
  // user's request.
  bool IsLastRange() const;

  // Extracts info from headers already stored in the cache. Returns false if
  // there is any problem with the headers. |truncated| should be true if we
  // have an incomplete 200 entry due to a transfer having been interrupted.
  // |writing_in_progress| should be set to true if a transfer for this entry's
  // payload is still in progress.
  bool UpdateFromStoredHeaders(const HttpResponseHeaders* headers,
                               disk_cache::Entry* entry,
                               bool truncated,
                               bool writing_in_progress);

  // Sets the byte current range to start again at zero (for a truncated entry).
  void SetRangeToStartDownload();

  // Returns true if the requested range is valid given the stored data.
  bool IsRequestedRangeOK();

  // Returns true if the response headers match what we expect, false otherwise.
  bool ResponseHeadersOK(const HttpResponseHeaders* headers);

  // Fixes the response headers to include the right content length and range.
  // |success| is the result of the whole request so if it's false, we'll change
  // the result code to be 416.
  void FixResponseHeaders(HttpResponseHeaders* headers, bool success);

  // Fixes the content length that we want to store in the cache.
  void FixContentLength(HttpResponseHeaders* headers);

  // Reads up to |data_len| bytes from the cache and stores them in the provided
  // buffer (|data|). Basically, this is just a wrapper around the API of the
  // cache that provides the right arguments for the current range. When the IO
  // operation completes, OnCacheReadCompleted() must be called with the result
  // of the operation.
  int CacheRead(disk_cache::Entry* entry,
                IOBuffer* data,
                int data_len,
                CompletionOnceCallback callback);

  // Writes |data_len| bytes to cache. This is basically a wrapper around the
  // API of the cache that provides the right arguments for the current range.
  int CacheWrite(disk_cache::Entry* entry,
                 IOBuffer* data,
                 int data_len,
                 CompletionOnceCallback callback);

  // This method should be called when CacheRead() finishes the read, to update
  // the internal state about the current range.
  void OnCacheReadCompleted(int result);

  // This method should be called after receiving data from the network, to
  // update the internal state about the current range.
  void OnNetworkReadCompleted(int result);

  bool initial_validation() const { return initial_validation_; }

  bool range_requested() const { return range_requested_; }

 private:
  // Returns the length to use when scanning the cache.
  int GetNextRangeLen();

  // Completion routine for our callback.
  void GetAvailableRangeCompleted(const disk_cache::RangeResult& result);

  // The portion we're trying to get, either from cache or network.
  int64_t current_range_start_ = 0;
  int64_t current_range_end_ = 0;

  // Next portion available in the cache --- this may be what's currently being
  // read, or the next thing that will be read if the current network portion
  // succeeds.
  //
  // |cached_start_| represents the beginning of the range, while
  // |cached_min_len_| the data not yet read (possibly overestimated). It may
  // also have an error code latched into it.
  int64_t cached_start_ = 0;
  int cached_min_len_ = 0;

  // The size of the whole file.
  int64_t resource_size_ = 0;
  HttpByteRange byte_range_;  // The range requested by the user.
  // The clean set of extra headers (no ranges).
  HttpRequestHeaders extra_headers_;
  bool range_requested_ = false;  // ###
  bool range_present_ = false;    // True if next range entry is already stored.
  bool final_range_ = false;
  bool sparse_entry_ = true;
  bool truncated_ = false;           // We have an incomplete 200 stored.
  bool initial_validation_ = false;  // Only used for truncated entries.
  CompletionOnceCallback callback_;
  base::WeakPtrFactory<PartialData> weak_factory_{this};
};

}  // namespace net

#endif  // NET_HTTP_PARTIAL_DATA_H_