OLD | NEW |
| (Empty) |
1 // Copyright 2014 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 #include "net/filter/gzip_header.h" | |
6 | |
7 #include <algorithm> | |
8 | |
9 #include "base/logging.h" | |
10 #include "third_party/zlib/zlib.h" | |
11 | |
12 namespace net { | |
13 | |
14 const uint8 GZipHeader::magic[] = { 0x1f, 0x8b }; | |
15 | |
16 GZipHeader::GZipHeader() { | |
17 Reset(); | |
18 } | |
19 | |
20 GZipHeader::~GZipHeader() { | |
21 } | |
22 | |
23 void GZipHeader::Reset() { | |
24 state_ = IN_HEADER_ID1; | |
25 flags_ = 0; | |
26 extra_length_ = 0; | |
27 } | |
28 | |
29 GZipHeader::Status GZipHeader::ReadMore(const char* inbuf, int inbuf_len, | |
30 const char** header_end) { | |
31 DCHECK_GE(inbuf_len, 0); | |
32 const uint8* pos = reinterpret_cast<const uint8*>(inbuf); | |
33 const uint8* const end = pos + inbuf_len; | |
34 | |
35 while ( pos < end ) { | |
36 switch ( state_ ) { | |
37 case IN_HEADER_ID1: | |
38 if ( *pos != magic[0] ) return INVALID_HEADER; | |
39 pos++; | |
40 state_++; | |
41 break; | |
42 case IN_HEADER_ID2: | |
43 if ( *pos != magic[1] ) return INVALID_HEADER; | |
44 pos++; | |
45 state_++; | |
46 break; | |
47 case IN_HEADER_CM: | |
48 if ( *pos != Z_DEFLATED ) return INVALID_HEADER; | |
49 pos++; | |
50 state_++; | |
51 break; | |
52 case IN_HEADER_FLG: | |
53 flags_ = (*pos) & (FLAG_FHCRC | FLAG_FEXTRA | | |
54 FLAG_FNAME | FLAG_FCOMMENT); | |
55 pos++; | |
56 state_++; | |
57 break; | |
58 | |
59 case IN_HEADER_MTIME_BYTE_0: | |
60 pos++; | |
61 state_++; | |
62 break; | |
63 case IN_HEADER_MTIME_BYTE_1: | |
64 pos++; | |
65 state_++; | |
66 break; | |
67 case IN_HEADER_MTIME_BYTE_2: | |
68 pos++; | |
69 state_++; | |
70 break; | |
71 case IN_HEADER_MTIME_BYTE_3: | |
72 pos++; | |
73 state_++; | |
74 break; | |
75 | |
76 case IN_HEADER_XFL: | |
77 pos++; | |
78 state_++; | |
79 break; | |
80 | |
81 case IN_HEADER_OS: | |
82 pos++; | |
83 state_++; | |
84 break; | |
85 | |
86 case IN_XLEN_BYTE_0: | |
87 if ( !(flags_ & FLAG_FEXTRA) ) { | |
88 state_ = IN_FNAME; | |
89 break; | |
90 } | |
91 // We have a two-byte little-endian length, followed by a | |
92 // field of that length. | |
93 extra_length_ = *pos; | |
94 pos++; | |
95 state_++; | |
96 break; | |
97 case IN_XLEN_BYTE_1: | |
98 extra_length_ += *pos << 8; | |
99 pos++; | |
100 state_++; | |
101 // We intentionally fall through, because if we have a | |
102 // zero-length FEXTRA, we want to check to notice that we're | |
103 // done reading the FEXTRA before we exit this loop... | |
104 | |
105 case IN_FEXTRA: { | |
106 // Grab the rest of the bytes in the extra field, or as many | |
107 // of them as are actually present so far. | |
108 const uint16 num_extra_bytes = static_cast<uint16>(std::min( | |
109 static_cast<ptrdiff_t>(extra_length_), | |
110 (end - pos))); | |
111 pos += num_extra_bytes; | |
112 extra_length_ -= num_extra_bytes; | |
113 if ( extra_length_ == 0 ) { | |
114 state_ = IN_FNAME; // advance when we've seen extra_length_ bytes | |
115 flags_ &= ~FLAG_FEXTRA; // we're done with the FEXTRA stuff | |
116 } | |
117 break; | |
118 } | |
119 | |
120 case IN_FNAME: | |
121 if ( !(flags_ & FLAG_FNAME) ) { | |
122 state_ = IN_FCOMMENT; | |
123 break; | |
124 } | |
125 // See if we can find the end of the \0-terminated FNAME field. | |
126 pos = reinterpret_cast<const uint8*>(memchr(pos, '\0', (end - pos))); | |
127 if ( pos != NULL ) { | |
128 pos++; // advance past the '\0' | |
129 flags_ &= ~FLAG_FNAME; // we're done with the FNAME stuff | |
130 state_ = IN_FCOMMENT; | |
131 } else { | |
132 pos = end; // everything we have so far is part of the FNAME | |
133 } | |
134 break; | |
135 | |
136 case IN_FCOMMENT: | |
137 if ( !(flags_ & FLAG_FCOMMENT) ) { | |
138 state_ = IN_FHCRC_BYTE_0; | |
139 break; | |
140 } | |
141 // See if we can find the end of the \0-terminated FCOMMENT field. | |
142 pos = reinterpret_cast<const uint8*>(memchr(pos, '\0', (end - pos))); | |
143 if ( pos != NULL ) { | |
144 pos++; // advance past the '\0' | |
145 flags_ &= ~FLAG_FCOMMENT; // we're done with the FCOMMENT stuff | |
146 state_ = IN_FHCRC_BYTE_0; | |
147 } else { | |
148 pos = end; // everything we have so far is part of the FNAME | |
149 } | |
150 break; | |
151 | |
152 case IN_FHCRC_BYTE_0: | |
153 if ( !(flags_ & FLAG_FHCRC) ) { | |
154 state_ = IN_DONE; | |
155 break; | |
156 } | |
157 pos++; | |
158 state_++; | |
159 break; | |
160 | |
161 case IN_FHCRC_BYTE_1: | |
162 pos++; | |
163 flags_ &= ~FLAG_FHCRC; // we're done with the FHCRC stuff | |
164 state_++; | |
165 break; | |
166 | |
167 case IN_DONE: | |
168 *header_end = reinterpret_cast<const char*>(pos); | |
169 return COMPLETE_HEADER; | |
170 } | |
171 } | |
172 | |
173 if ( (state_ > IN_HEADER_OS) && (flags_ == 0) ) { | |
174 *header_end = reinterpret_cast<const char*>(pos); | |
175 return COMPLETE_HEADER; | |
176 } else { | |
177 return INCOMPLETE_HEADER; | |
178 } | |
179 } | |
180 | |
181 } // namespace net | |
OLD | NEW |