| OLD | NEW |
| (Empty) |
| 1 // Copyright 2017 The Crashpad Authors. All rights reserved. | |
| 2 // | |
| 3 // Licensed under the Apache License, Version 2.0 (the "License"); | |
| 4 // you may not use this file except in compliance with the License. | |
| 5 // You may obtain a copy of the License at | |
| 6 // | |
| 7 // http://www.apache.org/licenses/LICENSE-2.0 | |
| 8 // | |
| 9 // Unless required by applicable law or agreed to in writing, software | |
| 10 // distributed under the License is distributed on an "AS IS" BASIS, | |
| 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| 12 // See the License for the specific language governing permissions and | |
| 13 // limitations under the License. | |
| 14 | |
| 15 #include "util/net/http_body_gzip.h" | |
| 16 | |
| 17 #include <utility> | |
| 18 | |
| 19 #include "base/logging.h" | |
| 20 #include "base/numerics/safe_conversions.h" | |
| 21 #include "third_party/zlib/zlib_crashpad.h" | |
| 22 #include "util/misc/zlib.h" | |
| 23 | |
| 24 namespace crashpad { | |
| 25 | |
| 26 GzipHTTPBodyStream::GzipHTTPBodyStream(std::unique_ptr<HTTPBodyStream> source) | |
| 27 : input_(), | |
| 28 source_(std::move(source)), | |
| 29 z_stream_(new z_stream()), | |
| 30 state_(State::kUninitialized) {} | |
| 31 | |
| 32 GzipHTTPBodyStream::~GzipHTTPBodyStream() { | |
| 33 DCHECK(state_ == State::kUninitialized || | |
| 34 state_ == State::kFinished || | |
| 35 state_ == State::kError); | |
| 36 } | |
| 37 | |
| 38 FileOperationResult GzipHTTPBodyStream::GetBytesBuffer(uint8_t* buffer, | |
| 39 size_t max_len) { | |
| 40 if (state_ == State::kError) { | |
| 41 return -1; | |
| 42 } | |
| 43 | |
| 44 if (state_ == State::kFinished) { | |
| 45 return 0; | |
| 46 } | |
| 47 | |
| 48 if (state_ == State::kUninitialized) { | |
| 49 z_stream_->zalloc = Z_NULL; | |
| 50 z_stream_->zfree = Z_NULL; | |
| 51 z_stream_->opaque = Z_NULL; | |
| 52 | |
| 53 // The default values for zlib’s internal MAX_WBITS and DEF_MEM_LEVEL. These | |
| 54 // are the values that deflateInit() would use, but they’re not exported | |
| 55 // from zlib. deflateInit2() is used instead of deflateInit() to get the | |
| 56 // gzip wrapper. | |
| 57 const int kZlibMaxWindowBits = 15; | |
| 58 const int kZlibDefaultMemoryLevel = 8; | |
| 59 | |
| 60 int zr = deflateInit2(z_stream_.get(), | |
| 61 Z_DEFAULT_COMPRESSION, | |
| 62 Z_DEFLATED, | |
| 63 ZlibWindowBitsWithGzipWrapper(kZlibMaxWindowBits), | |
| 64 kZlibDefaultMemoryLevel, | |
| 65 Z_DEFAULT_STRATEGY); | |
| 66 if (zr != Z_OK) { | |
| 67 LOG(ERROR) << "deflateInit2: " << ZlibErrorString(zr); | |
| 68 state_ = State::kError; | |
| 69 return -1; | |
| 70 } | |
| 71 | |
| 72 state_ = State::kOperating; | |
| 73 } | |
| 74 | |
| 75 z_stream_->next_out = buffer; | |
| 76 z_stream_->avail_out = base::saturated_cast<uInt>(max_len); | |
| 77 | |
| 78 while (state_ != State::kFinished && z_stream_->avail_out > 0) { | |
| 79 if (state_ != State::kInputEOF && z_stream_->avail_in == 0) { | |
| 80 FileOperationResult input_bytes = | |
| 81 source_->GetBytesBuffer(input_, sizeof(input_)); | |
| 82 if (input_bytes == -1) { | |
| 83 Done(State::kError); | |
| 84 return -1; | |
| 85 } | |
| 86 | |
| 87 if (input_bytes == 0) { | |
| 88 state_ = State::kInputEOF; | |
| 89 } | |
| 90 | |
| 91 z_stream_->next_in = input_; | |
| 92 z_stream_->avail_in = base::checked_cast<uInt>(input_bytes); | |
| 93 } | |
| 94 | |
| 95 int zr = deflate(z_stream_.get(), | |
| 96 state_ == State::kInputEOF ? Z_FINISH : Z_NO_FLUSH); | |
| 97 if (state_ == State::kInputEOF && zr == Z_STREAM_END) { | |
| 98 Done(State::kFinished); | |
| 99 if (state_ == State::kError) { | |
| 100 return -1; | |
| 101 } | |
| 102 } else if (zr != Z_OK) { | |
| 103 LOG(ERROR) << "deflate: " << ZlibErrorString(zr); | |
| 104 Done(State::kError); | |
| 105 return -1; | |
| 106 } | |
| 107 } | |
| 108 | |
| 109 DCHECK_LE(z_stream_->avail_out, max_len); | |
| 110 return max_len - z_stream_->avail_out; | |
| 111 } | |
| 112 | |
| 113 void GzipHTTPBodyStream::Done(State state) { | |
| 114 DCHECK(state_ == State::kOperating || state_ == State::kInputEOF) << state_; | |
| 115 DCHECK(state == State::kFinished || state == State::kError) << state; | |
| 116 | |
| 117 int zr = deflateEnd(z_stream_.get()); | |
| 118 if (zr != Z_OK) { | |
| 119 LOG(ERROR) << "deflateEnd: " << ZlibErrorString(zr); | |
| 120 state_ = State::kError; | |
| 121 } else { | |
| 122 state_ = state; | |
| 123 } | |
| 124 } | |
| 125 | |
| 126 } // namespace crashpad | |
| OLD | NEW |