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 19 GZipHeader::GZipHeader() { 20 Reset(); 21 } 22 23 GZipHeader::~GZipHeader() { 24 } 25 26 void GZipHeader::Reset() { 27 state_ = IN_HEADER_ID1; 28 flags_ = 0; 29 extra_length_ = 0; 30 } 31 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