gzip_header.cc 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  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. #include "net/filter/gzip_header.h"
  5. #include <string.h>
  6. #include <algorithm>
  7. #include "base/check_op.h"
  8. #include "third_party/zlib/zlib.h"
  9. namespace net {
  10. const uint8_t GZipHeader::magic[] = {0x1f, 0x8b};
  11. GZipHeader::GZipHeader() {
  12. Reset();
  13. }
  14. GZipHeader::~GZipHeader() = default;
  15. void GZipHeader::Reset() {
  16. state_ = IN_HEADER_ID1;
  17. flags_ = 0;
  18. extra_length_ = 0;
  19. }
  20. GZipHeader::Status GZipHeader::ReadMore(const char* inbuf,
  21. size_t inbuf_len,
  22. const char** header_end) {
  23. const uint8_t* pos = reinterpret_cast<const uint8_t*>(inbuf);
  24. const uint8_t* const end = pos + inbuf_len;
  25. while ( pos < end ) {
  26. switch ( state_ ) {
  27. case IN_HEADER_ID1:
  28. if ( *pos != magic[0] ) return INVALID_HEADER;
  29. pos++;
  30. state_++;
  31. break;
  32. case IN_HEADER_ID2:
  33. if ( *pos != magic[1] ) return INVALID_HEADER;
  34. pos++;
  35. state_++;
  36. break;
  37. case IN_HEADER_CM:
  38. if ( *pos != Z_DEFLATED ) return INVALID_HEADER;
  39. pos++;
  40. state_++;
  41. break;
  42. case IN_HEADER_FLG:
  43. flags_ = (*pos) & (FLAG_FHCRC | FLAG_FEXTRA |
  44. FLAG_FNAME | FLAG_FCOMMENT);
  45. pos++;
  46. state_++;
  47. break;
  48. case IN_HEADER_MTIME_BYTE_0:
  49. pos++;
  50. state_++;
  51. break;
  52. case IN_HEADER_MTIME_BYTE_1:
  53. pos++;
  54. state_++;
  55. break;
  56. case IN_HEADER_MTIME_BYTE_2:
  57. pos++;
  58. state_++;
  59. break;
  60. case IN_HEADER_MTIME_BYTE_3:
  61. pos++;
  62. state_++;
  63. break;
  64. case IN_HEADER_XFL:
  65. pos++;
  66. state_++;
  67. break;
  68. case IN_HEADER_OS:
  69. pos++;
  70. state_++;
  71. break;
  72. case IN_XLEN_BYTE_0:
  73. if ( !(flags_ & FLAG_FEXTRA) ) {
  74. state_ = IN_FNAME;
  75. break;
  76. }
  77. // We have a two-byte little-endian length, followed by a
  78. // field of that length.
  79. extra_length_ = *pos;
  80. pos++;
  81. state_++;
  82. break;
  83. case IN_XLEN_BYTE_1:
  84. extra_length_ += *pos << 8;
  85. pos++;
  86. state_++;
  87. // We intentionally fall through, because if we have a
  88. // zero-length FEXTRA, we want to check to notice that we're
  89. // done reading the FEXTRA before we exit this loop...
  90. [[fallthrough]];
  91. case IN_FEXTRA: {
  92. // Grab the rest of the bytes in the extra field, or as many
  93. // of them as are actually present so far.
  94. const uint16_t num_extra_bytes = static_cast<uint16_t>(
  95. std::min(static_cast<ptrdiff_t>(extra_length_), (end - pos)));
  96. pos += num_extra_bytes;
  97. extra_length_ -= num_extra_bytes;
  98. if ( extra_length_ == 0 ) {
  99. state_ = IN_FNAME; // advance when we've seen extra_length_ bytes
  100. flags_ &= ~FLAG_FEXTRA; // we're done with the FEXTRA stuff
  101. }
  102. break;
  103. }
  104. case IN_FNAME:
  105. if ( !(flags_ & FLAG_FNAME) ) {
  106. state_ = IN_FCOMMENT;
  107. break;
  108. }
  109. // See if we can find the end of the \0-terminated FNAME field.
  110. pos = reinterpret_cast<const uint8_t*>(memchr(pos, '\0', (end - pos)));
  111. if (pos != nullptr) {
  112. pos++; // advance past the '\0'
  113. flags_ &= ~FLAG_FNAME; // we're done with the FNAME stuff
  114. state_ = IN_FCOMMENT;
  115. } else {
  116. pos = end; // everything we have so far is part of the FNAME
  117. }
  118. break;
  119. case IN_FCOMMENT:
  120. if ( !(flags_ & FLAG_FCOMMENT) ) {
  121. state_ = IN_FHCRC_BYTE_0;
  122. break;
  123. }
  124. // See if we can find the end of the \0-terminated FCOMMENT field.
  125. pos = reinterpret_cast<const uint8_t*>(memchr(pos, '\0', (end - pos)));
  126. if (pos != nullptr) {
  127. pos++; // advance past the '\0'
  128. flags_ &= ~FLAG_FCOMMENT; // we're done with the FCOMMENT stuff
  129. state_ = IN_FHCRC_BYTE_0;
  130. } else {
  131. pos = end; // everything we have so far is part of the FNAME
  132. }
  133. break;
  134. case IN_FHCRC_BYTE_0:
  135. if ( !(flags_ & FLAG_FHCRC) ) {
  136. state_ = IN_DONE;
  137. break;
  138. }
  139. pos++;
  140. state_++;
  141. break;
  142. case IN_FHCRC_BYTE_1:
  143. pos++;
  144. flags_ &= ~FLAG_FHCRC; // we're done with the FHCRC stuff
  145. state_++;
  146. break;
  147. case IN_DONE:
  148. *header_end = reinterpret_cast<const char*>(pos);
  149. return COMPLETE_HEADER;
  150. }
  151. }
  152. if ( (state_ > IN_HEADER_OS) && (flags_ == 0) ) {
  153. *header_end = reinterpret_cast<const char*>(pos);
  154. return COMPLETE_HEADER;
  155. } else {
  156. return INCOMPLETE_HEADER;
  157. }
  158. }
  159. } // namespace net