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