1 // Copyright (c) 2006-2008 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 // Filter performs filtering on data streams. Sample usage: 6 // 7 // IStream* pre_filter_source; 8 // ... 9 // Filter* filter = Filter::Factory(filter_type, size); 10 // int pre_filter_data_len = filter->stream_buffer_size(); 11 // pre_filter_source->read(filter->stream_buffer(), pre_filter_data_len); 12 // 13 // filter->FlushStreamBuffer(pre_filter_data_len); 14 // 15 // char post_filter_buf[kBufferSize]; 16 // int post_filter_data_len = kBufferSize; 17 // filter->ReadFilteredData(post_filter_buf, &post_filter_data_len); 18 // 19 // To filter a data stream, the caller first gets filter's stream_buffer_ 20 // through its accessor and fills in stream_buffer_ with pre-filter data, next 21 // calls FlushStreamBuffer to notify Filter, then calls ReadFilteredData 22 // repeatedly to get all the filtered data. After all data have been fitlered 23 // and read out, the caller may fill in stream_buffer_ again. This 24 // WriteBuffer-Flush-Read cycle is repeated until reaching the end of data 25 // stream. 26 // 27 // The lifetime of a Filter instance is completely controlled by its caller. 28 29 #ifndef NET_BASE_FILTER_H__ 30 #define NET_BASE_FILTER_H__ 31 32 #include <string> 33 #include <vector> 34 35 #include "base/basictypes.h" 36 #include "base/ref_counted.h" 37 #include "base/scoped_ptr.h" 38 #include "base/time.h" 39 #include "testing/gtest/include/gtest/gtest_prod.h" 40 41 class GURL; 42 43 namespace net { 44 class IOBuffer; 45 } 46 47 //------------------------------------------------------------------------------ 48 // Define an interface class that allows access to contextual information 49 // supplied by the owner of this filter. In the case where there are a chain of 50 // filters, there is only one owner of all the chained filters, and that context 51 // is passed to the constructor of all those filters. To be clear, the context 52 // does NOT reflect the position in a chain, or the fact that there are prior 53 // or later filters in a chain. 54 class FilterContext { 55 public: 56 // Enum to control what histograms are emitted near end-of-life of this 57 // instance. 58 enum StatisticSelector { 59 SDCH_DECODE, 60 SDCH_PASSTHROUGH, 61 SDCH_EXPERIMENT_DECODE, 62 SDCH_EXPERIMENT_HOLDBACK, 63 }; 64 ~FilterContext()65 virtual ~FilterContext() {} 66 67 // What mime type was specified in the header for this data? 68 // Only makes senses for some types of contexts, and returns false 69 // when not applicable. 70 virtual bool GetMimeType(std::string* mime_type) const = 0; 71 72 // What URL was used to access this data? 73 // Return false if gurl is not present. 74 virtual bool GetURL(GURL* gurl) const = 0; 75 76 // When was this data requested from a server? 77 virtual base::Time GetRequestTime() const = 0; 78 79 // Is data supplied from cache, or fresh across the net? 80 virtual bool IsCachedContent() const = 0; 81 82 // Is this a download? 83 virtual bool IsDownload() const = 0; 84 85 // Was this data flagged as a response to a request with an SDCH dictionary? 86 virtual bool IsSdchResponse() const = 0; 87 88 // How many bytes were read from the net or cache so far (and potentially 89 // pushed into a filter for processing)? 90 virtual int64 GetByteReadCount() const = 0; 91 92 // What response code was received with the associated network transaction? 93 // For example: 200 is ok. 4xx are error codes. etc. 94 virtual int GetResponseCode() const = 0; 95 96 // What is the desirable input buffer size for these filters? 97 // This value is currently supplied by the context, and is constant for all 98 // filters, even when they are part of a chain of filters. (i.e., we currently 99 // don't change the input buffer sizes for a linked chain of filters, and the 100 // buffer size for input to all filters in a chain is this one constant). 101 virtual int GetInputStreamBufferSize() const = 0; 102 103 // The following method forces the context to emit a specific set of 104 // statistics as selected by the argument. 105 virtual void RecordPacketStats(StatisticSelector statistic) const = 0; 106 }; 107 108 //------------------------------------------------------------------------------ 109 class Filter { 110 public: 111 // Return values of function ReadFilteredData. 112 enum FilterStatus { 113 // Read filtered data successfully 114 FILTER_OK, 115 // Read filtered data successfully, and the data in the buffer has been 116 // consumed by the filter, but more data is needed in order to continue 117 // filtering. At this point, the caller is free to reuse the filter 118 // buffer to provide more data. 119 FILTER_NEED_MORE_DATA, 120 // Read filtered data successfully, and filter reaches the end of the data 121 // stream. 122 FILTER_DONE, 123 // There is an error during filtering. 124 FILTER_ERROR 125 }; 126 127 // Specifies type of filters that can be created. 128 enum FilterType { 129 FILTER_TYPE_DEFLATE, 130 FILTER_TYPE_GZIP, 131 FILTER_TYPE_GZIP_HELPING_SDCH, // Gzip possible, but pass through allowed. 132 FILTER_TYPE_SDCH, 133 FILTER_TYPE_SDCH_POSSIBLE, // Sdch possible, but pass through allowed. 134 FILTER_TYPE_UNSUPPORTED, 135 }; 136 137 virtual ~Filter(); 138 139 // Creates a Filter object. 140 // Parameters: Filter_types specifies the type of filter created; 141 // filter_context allows filters to acquire additional details needed for 142 // construction and operation, such as a specification of requisite input 143 // buffer size. 144 // If success, the function returns the pointer to the Filter object created. 145 // If failed or a filter is not needed, the function returns NULL. 146 // 147 // Note: filter_types is an array of filter names (content encoding types as 148 // provided in an HTTP header), which will be chained together serially to do 149 // successive filtering of data. The names in the vector are ordered based on 150 // encoding order, and the filters are chained to operate in the reverse 151 // (decoding) order. For example, types[0] = "sdch", types[1] = "gzip" will 152 // cause data to first be gunizip filtered, and the resulting output from that 153 // filter will be sdch decoded. 154 static Filter* Factory(const std::vector<FilterType>& filter_types, 155 const FilterContext& filter_context); 156 157 // External call to obtain data from this filter chain. If ther is no 158 // next_filter_, then it obtains data from this specific filter. 159 FilterStatus ReadData(char* dest_buffer, int* dest_len); 160 161 // Returns a pointer to the stream_buffer_. stream_buffer()162 net::IOBuffer* stream_buffer() const { return stream_buffer_.get(); } 163 164 // Returns the maximum size of stream_buffer_ in number of chars. stream_buffer_size()165 int stream_buffer_size() const { return stream_buffer_size_; } 166 167 // Returns the total number of chars remaining in stream_buffer_ to be 168 // filtered. 169 // 170 // If the function returns 0 then all data has been filtered, and the caller 171 // is safe to copy new data into stream_buffer_. stream_data_len()172 int stream_data_len() const { return stream_data_len_; } 173 174 // Flushes stream_buffer_ for next round of filtering. After copying data to 175 // stream_buffer_, the caller should call this function to notify Filter to 176 // start filtering. Then after this function is called, the caller can get 177 // post-filtered data using ReadFilteredData. The caller must not write to 178 // stream_buffer_ and call this function again before stream_buffer_ is 179 // emptied out by ReadFilteredData. 180 // 181 // The input stream_data_len is the length (in number of chars) of valid 182 // data in stream_buffer_. It can not be greater than stream_buffer_size_. 183 // The function returns true if success, and false otherwise. 184 bool FlushStreamBuffer(int stream_data_len); 185 186 // Translate the text of a filter name (from Content-Encoding header) into a 187 // FilterType. 188 static FilterType ConvertEncodingToType(const std::string& filter_type); 189 190 // Given a array of encoding_types, try to do some error recovery adjustment 191 // to the list. This includes handling known bugs in the Apache server (where 192 // redundant gzip encoding is specified), as well as issues regarding SDCH 193 // encoding, where various proxies and anti-virus products modify or strip the 194 // encodings. These fixups require context, which includes whether this 195 // response was made to an SDCH request (i.e., an available dictionary was 196 // advertised in the GET), as well as the mime type of the content. 197 static void FixupEncodingTypes(const FilterContext& filter_context, 198 std::vector<FilterType>* encoding_types); 199 200 protected: 201 explicit Filter(const FilterContext& filter_context); 202 203 FRIEND_TEST(SdchFilterTest, ContentTypeId); 204 // Filters the data stored in stream_buffer_ and writes the output into the 205 // dest_buffer passed in. 206 // 207 // Upon entry, *dest_len is the total size (in number of chars) of the 208 // destination buffer. Upon exit, *dest_len is the actual number of chars 209 // written into the destination buffer. 210 // 211 // This function will fail if there is no pre-filter data in the 212 // stream_buffer_. On the other hand, *dest_len can be 0 upon successful 213 // return. For example, a decoding filter may process some pre-filter data 214 // but not produce output yet. 215 virtual FilterStatus ReadFilteredData(char* dest_buffer, int* dest_len); 216 217 // Copy pre-filter data directly to destination buffer without decoding. 218 FilterStatus CopyOut(char* dest_buffer, int* dest_len); 219 last_status()220 FilterStatus last_status() const { return last_status_; } 221 filter_context()222 const FilterContext& filter_context() const { return filter_context_; } 223 224 // Buffer to hold the data to be filtered (the input queue). 225 scoped_refptr<net::IOBuffer> stream_buffer_; 226 227 // Maximum size of stream_buffer_ in number of chars. 228 int stream_buffer_size_; 229 230 // Pointer to the next data in stream_buffer_ to be filtered. 231 char* next_stream_data_; 232 233 // Total number of remaining chars in stream_buffer_ to be filtered. 234 int stream_data_len_; 235 236 private: 237 // A factory helper for creating filters for within a chain of potentially 238 // multiple encodings. If a chain of filters is created, then this may be 239 // called multiple times during the filter creation process. In most simple 240 // cases, this is only called once. Returns NULL and cleans up (deleting 241 // filter_list) if a new filter can't be constructed. 242 static Filter* PrependNewFilter(FilterType type_id, 243 const FilterContext& filter_context, 244 Filter* filter_list); 245 246 // Allocates and initializes stream_buffer_ based on filter_context_. 247 // Establishes a buffer large enough to handle the amount specified in 248 // filter_context_.GetInputStreamBufferSize(). 249 bool InitBuffer(); 250 251 // Helper function to empty our output into the next filter's input. 252 void PushDataIntoNextFilter(); 253 254 // An optional filter to process output from this filter. 255 scoped_ptr<Filter> next_filter_; 256 // Remember what status or local filter last returned so we can better handle 257 // chained filters. 258 FilterStatus last_status_; 259 260 // Context data from the owner of this filter. Some filters need additional 261 // context information (mime type, etc.) to properly function, and they access 262 // this data via this reference member. 263 const FilterContext& filter_context_; 264 265 DISALLOW_COPY_AND_ASSIGN(Filter); 266 }; 267 268 #endif // NET_BASE_FILTER_H__ 269