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