Home | History | Annotate | Download | only in base
      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