• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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