Probably broke Win7 Tests (dbg)(6). http://build.chromium.org/p/chromium.win/builders...
[chromium-blink-merge.git] / net / filter / gzip_header.cc
blob4d1cad91489e4639f4296345d71e16c2cf266b21
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.
5 #include "net/filter/gzip_header.h"
7 #include <algorithm>
9 #include "base/logging.h"
10 #include "third_party/zlib/zlib.h"
12 namespace net {
14 const uint8 GZipHeader::magic[] = { 0x1f, 0x8b };
16 GZipHeader::GZipHeader() {
17 Reset();
20 GZipHeader::~GZipHeader() {
23 void GZipHeader::Reset() {
24 state_ = IN_HEADER_ID1;
25 flags_ = 0;
26 extra_length_ = 0;
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;
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;
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;
76 case IN_HEADER_XFL:
77 pos++;
78 state_++;
79 break;
81 case IN_HEADER_OS:
82 pos++;
83 state_++;
84 break;
86 case IN_XLEN_BYTE_0:
87 if ( !(flags_ & FLAG_FEXTRA) ) {
88 state_ = IN_FNAME;
89 break;
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...
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 int num_extra_bytes = static_cast<const int>(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
117 break;
120 case IN_FNAME:
121 if ( !(flags_ & FLAG_FNAME) ) {
122 state_ = IN_FCOMMENT;
123 break;
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
134 break;
136 case IN_FCOMMENT:
137 if ( !(flags_ & FLAG_FCOMMENT) ) {
138 state_ = IN_FHCRC_BYTE_0;
139 break;
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
150 break;
152 case IN_FHCRC_BYTE_0:
153 if ( !(flags_ & FLAG_FHCRC) ) {
154 state_ = IN_DONE;
155 break;
157 pos++;
158 state_++;
159 break;
161 case IN_FHCRC_BYTE_1:
162 pos++;
163 flags_ &= ~FLAG_FHCRC; // we're done with the FHCRC stuff
164 state_++;
165 break;
167 case IN_DONE:
168 *header_end = reinterpret_cast<const char*>(pos);
169 return COMPLETE_HEADER;
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;
181 } // namespace net