xref: /aosp_15_r20/external/cronet/net/tools/content_decoder_tool/content_decoder_tool.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2016 The Chromium Authors
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/containers/adapters.h"
11 #include "base/logging.h"
12 #include "base/strings/string_util.h"
13 #include "net/base/completion_once_callback.h"
14 #include "net/base/io_buffer.h"
15 #include "net/base/test_completion_callback.h"
16 #include "net/filter/brotli_source_stream.h"
17 #include "net/filter/gzip_source_stream.h"
18 #include "net/filter/source_stream.h"
19 
20 namespace net {
21 
22 namespace {
23 
24 const int kBufferLen = 4096;
25 
26 const char kDeflate[] = "deflate";
27 const char kGZip[] = "gzip";
28 const char kXGZip[] = "x-gzip";
29 const char kBrotli[] = "br";
30 
31 class StdinSourceStream : public SourceStream {
32  public:
StdinSourceStream(std::istream * input_stream)33   explicit StdinSourceStream(std::istream* input_stream)
34       : SourceStream(SourceStream::TYPE_NONE), input_stream_(input_stream) {}
35 
36   StdinSourceStream(const StdinSourceStream&) = delete;
37   StdinSourceStream& operator=(const StdinSourceStream&) = delete;
38 
39   ~StdinSourceStream() override = default;
40 
41   // SourceStream implementation.
Read(IOBuffer * dest_buffer,int buffer_size,CompletionOnceCallback callback)42   int Read(IOBuffer* dest_buffer,
43            int buffer_size,
44            CompletionOnceCallback callback) override {
45     if (input_stream_->eof())
46       return OK;
47     if (input_stream_) {
48       input_stream_->read(dest_buffer->data(), buffer_size);
49       int bytes = input_stream_->gcount();
50       return bytes;
51     }
52     return ERR_FAILED;
53   }
54 
Description() const55   std::string Description() const override { return ""; }
56 
MayHaveMoreBytes() const57   bool MayHaveMoreBytes() const override { return true; }
58 
59  private:
60   std::istream* input_stream_;
61 };
62 
63 }  // namespace
64 
65 // static
ContentDecoderToolProcessInput(std::vector<std::string> content_encodings,std::istream * input_stream,std::ostream * output_stream)66 bool ContentDecoderToolProcessInput(std::vector<std::string> content_encodings,
67                                     std::istream* input_stream,
68                                     std::ostream* output_stream) {
69   std::unique_ptr<SourceStream> upstream(
70       std::make_unique<StdinSourceStream>(input_stream));
71   for (const auto& content_encoding : base::Reversed(content_encodings)) {
72     std::unique_ptr<SourceStream> downstream;
73     if (base::EqualsCaseInsensitiveASCII(content_encoding, kBrotli)) {
74       downstream = CreateBrotliSourceStream(std::move(upstream));
75     } else if (base::EqualsCaseInsensitiveASCII(content_encoding, kDeflate)) {
76       downstream = GzipSourceStream::Create(std::move(upstream),
77                                             SourceStream::TYPE_DEFLATE);
78     } else if (base::EqualsCaseInsensitiveASCII(content_encoding, kGZip) ||
79                base::EqualsCaseInsensitiveASCII(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