1 // Copyright 2016 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/tools/content_decoder_tool/content_decoder_tool.h"
6
7 #include <memory>
8 #include <utility>
9
10 #include "base/logging.h"
11 #include "base/strings/string_util.h"
12 #include "net/base/completion_once_callback.h"
13 #include "net/base/io_buffer.h"
14 #include "net/base/test_completion_callback.h"
15 #include "net/filter/brotli_source_stream.h"
16 #include "net/filter/gzip_source_stream.h"
17 #include "net/filter/source_stream.h"
18
19 namespace net {
20
21 namespace {
22
23 const int kBufferLen = 4096;
24
25 const char kDeflate[] = "deflate";
26 const char kGZip[] = "gzip";
27 const char kXGZip[] = "x-gzip";
28 const char kBrotli[] = "br";
29
30 class StdinSourceStream : public SourceStream {
31 public:
StdinSourceStream(std::istream * input_stream)32 explicit StdinSourceStream(std::istream* input_stream)
33 : SourceStream(SourceStream::TYPE_NONE), input_stream_(input_stream) {}
34 ~StdinSourceStream() override = default;
35
36 // SourceStream implementation.
Read(IOBuffer * dest_buffer,int buffer_size,CompletionOnceCallback callback)37 int Read(IOBuffer* dest_buffer,
38 int buffer_size,
39 CompletionOnceCallback callback) override {
40 if (input_stream_->eof())
41 return OK;
42 if (input_stream_) {
43 input_stream_->read(dest_buffer->data(), buffer_size);
44 int bytes = input_stream_->gcount();
45 return bytes;
46 }
47 return ERR_FAILED;
48 }
49
Description() const50 std::string Description() const override { return ""; }
51
MayHaveMoreBytes() const52 bool MayHaveMoreBytes() const override { return true; }
53
54 private:
55 std::istream* input_stream_;
56
57 DISALLOW_COPY_AND_ASSIGN(StdinSourceStream);
58 };
59
60 } // namespace
61
62 // static
ContentDecoderToolProcessInput(std::vector<std::string> content_encodings,std::istream * input_stream,std::ostream * output_stream)63 bool ContentDecoderToolProcessInput(std::vector<std::string> content_encodings,
64 std::istream* input_stream,
65 std::ostream* output_stream) {
66 std::unique_ptr<SourceStream> upstream(
67 std::make_unique<StdinSourceStream>(input_stream));
68 for (std::vector<std::string>::const_reverse_iterator riter =
69 content_encodings.rbegin();
70 riter != content_encodings.rend(); ++riter) {
71 std::string content_encoding = *riter;
72 std::unique_ptr<SourceStream> downstream = nullptr;
73 if (base::LowerCaseEqualsASCII(content_encoding, kBrotli)) {
74 downstream = CreateBrotliSourceStream(std::move(upstream));
75 } else if (base::LowerCaseEqualsASCII(content_encoding, kDeflate)) {
76 downstream = GzipSourceStream::Create(std::move(upstream),
77 SourceStream::TYPE_DEFLATE);
78 } else if (base::LowerCaseEqualsASCII(content_encoding, kGZip) ||
79 base::LowerCaseEqualsASCII(content_encoding, kXGZip)) {
80 downstream = GzipSourceStream::Create(std::move(upstream),
81 SourceStream::TYPE_GZIP);
82 } else {
83 LOG(ERROR) << "Unsupported decoder '" << content_encoding << "'.";
84 return false;
85 }
86 if (downstream == nullptr) {
87 LOG(ERROR) << "Couldn't create the decoder.";
88 return false;
89 }
90 upstream = std::move(downstream);
91 }
92 if (!upstream) {
93 LOG(ERROR) << "Couldn't create the decoder.";
94 return false;
95 }
96 scoped_refptr<IOBuffer> read_buffer =
97 base::MakeRefCounted<IOBufferWithSize>(kBufferLen);
98 while (true) {
99 TestCompletionCallback callback;
100 int bytes_read =
101 upstream->Read(read_buffer.get(), kBufferLen, callback.callback());
102 if (bytes_read == ERR_IO_PENDING)
103 bytes_read = callback.WaitForResult();
104
105 if (bytes_read < 0) {
106 LOG(ERROR) << "Couldn't decode stdin.";
107 return false;
108 }
109 output_stream->write(read_buffer->data(), bytes_read);
110 // If EOF is read, break out the while loop.
111 if (bytes_read == 0)
112 break;
113 }
114 return true;
115 }
116
117 } // namespace net
118