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 #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 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 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 182