Home | History | Annotate | Download | only in filter
      1 // Copyright 2014 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/filter/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