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