15d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "net/filter/gzip_header.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
74e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include <algorithm>
84e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "third_party/zlib/zlib.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace net {
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const uint8 GZipHeader::magic[] = { 0x1f, 0x8b };
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)GZipHeader::GZipHeader() {
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Reset();
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)GZipHeader::~GZipHeader() {
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void GZipHeader::Reset() {
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  state_        = IN_HEADER_ID1;
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  flags_        = 0;
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  extra_length_ = 0;
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)GZipHeader::Status GZipHeader::ReadMore(const char* inbuf, int inbuf_len,
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                        const char** header_end) {
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_GE(inbuf_len, 0);
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const uint8* pos = reinterpret_cast<const uint8*>(inbuf);
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const uint8* const end = pos + inbuf_len;
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while ( pos < end ) {
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    switch ( state_ ) {
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case IN_HEADER_ID1:
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if ( *pos != magic[0] )  return INVALID_HEADER;
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        pos++;
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        state_++;
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case IN_HEADER_ID2:
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if ( *pos != magic[1] )  return INVALID_HEADER;
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        pos++;
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        state_++;
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case IN_HEADER_CM:
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if ( *pos != Z_DEFLATED )  return INVALID_HEADER;
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        pos++;
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        state_++;
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case IN_HEADER_FLG:
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        flags_ = (*pos) & (FLAG_FHCRC | FLAG_FEXTRA |
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           FLAG_FNAME | FLAG_FCOMMENT);
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        pos++;
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        state_++;
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case IN_HEADER_MTIME_BYTE_0:
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        pos++;
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        state_++;
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case IN_HEADER_MTIME_BYTE_1:
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        pos++;
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        state_++;
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case IN_HEADER_MTIME_BYTE_2:
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        pos++;
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        state_++;
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case IN_HEADER_MTIME_BYTE_3:
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        pos++;
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        state_++;
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case IN_HEADER_XFL:
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        pos++;
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        state_++;
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case IN_HEADER_OS:
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        pos++;
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        state_++;
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case IN_XLEN_BYTE_0:
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if ( !(flags_ & FLAG_FEXTRA) ) {
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          state_ = IN_FNAME;
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          break;
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // We have a two-byte little-endian length, followed by a
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // field of that length.
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        extra_length_ = *pos;
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        pos++;
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        state_++;
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case IN_XLEN_BYTE_1:
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        extra_length_ += *pos << 8;
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        pos++;
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        state_++;
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // We intentionally fall through, because if we have a
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // zero-length FEXTRA, we want to check to notice that we're
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // done reading the FEXTRA before we exit this loop...
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case IN_FEXTRA: {
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Grab the rest of the bytes in the extra field, or as many
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // of them as are actually present so far.
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        const int num_extra_bytes = static_cast<const int>(std::min(
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            static_cast<ptrdiff_t>(extra_length_),
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            (end - pos)));
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        pos += num_extra_bytes;
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        extra_length_ -= num_extra_bytes;
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if ( extra_length_ == 0 ) {
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          state_ = IN_FNAME;   // advance when we've seen extra_length_ bytes
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          flags_ &= ~FLAG_FEXTRA;   // we're done with the FEXTRA stuff
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case IN_FNAME:
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if ( !(flags_ & FLAG_FNAME) ) {
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          state_ = IN_FCOMMENT;
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          break;
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // See if we can find the end of the \0-terminated FNAME field.
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        pos = reinterpret_cast<const uint8*>(memchr(pos, '\0', (end - pos)));
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if ( pos != NULL ) {
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          pos++;  // advance past the '\0'
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          flags_ &= ~FLAG_FNAME;   // we're done with the FNAME stuff
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          state_ = IN_FCOMMENT;
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        } else {
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          pos = end;  // everything we have so far is part of the FNAME
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case IN_FCOMMENT:
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if ( !(flags_ & FLAG_FCOMMENT) ) {
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          state_ = IN_FHCRC_BYTE_0;
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          break;
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // See if we can find the end of the \0-terminated FCOMMENT field.
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        pos = reinterpret_cast<const uint8*>(memchr(pos, '\0', (end - pos)));
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if ( pos != NULL ) {
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          pos++;  // advance past the '\0'
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          flags_ &= ~FLAG_FCOMMENT;   // we're done with the FCOMMENT stuff
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          state_ = IN_FHCRC_BYTE_0;
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        } else {
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          pos = end;  // everything we have so far is part of the FNAME
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case IN_FHCRC_BYTE_0:
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if ( !(flags_ & FLAG_FHCRC) ) {
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          state_ = IN_DONE;
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          break;
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        pos++;
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        state_++;
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case IN_FHCRC_BYTE_1:
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        pos++;
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        flags_ &= ~FLAG_FHCRC;   // we're done with the FHCRC stuff
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        state_++;
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case IN_DONE:
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        *header_end = reinterpret_cast<const char*>(pos);
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return COMPLETE_HEADER;
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if ( (state_ > IN_HEADER_OS) && (flags_ == 0) ) {
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *header_end = reinterpret_cast<const char*>(pos);
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return COMPLETE_HEADER;
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return INCOMPLETE_HEADER;
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace net
182