ppd_line_reader.cc 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. // Copyright 2017 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 "chromeos/printing/ppd_line_reader.h"
  5. #include <memory>
  6. #include <string>
  7. #include <utility>
  8. #include "base/bind.h"
  9. #include "base/strings/string_util.h"
  10. #include "net/base/completion_once_callback.h"
  11. #include "net/base/io_buffer.h"
  12. #include "net/filter/gzip_header.h"
  13. #include "net/filter/gzip_source_stream.h"
  14. #include "net/filter/source_stream.h"
  15. namespace chromeos {
  16. namespace {
  17. constexpr char kPPDMagicNumberString[] = "*PPD-Adobe:";
  18. // Return true if contents has a valid Gzip header.
  19. bool IsGZipped(const std::string& contents) {
  20. const char* unused;
  21. return net::GZipHeader().ReadMore(contents.data(), contents.size(),
  22. &unused) ==
  23. net::GZipHeader::COMPLETE_HEADER;
  24. }
  25. // Return true if c is a newline in the ppd sense, that is, either newline or
  26. // carriage return.
  27. bool IsNewline(char c) {
  28. return c == '\n' || c == '\r';
  29. }
  30. // Source stream that reads from a string. A reference is taken to the string
  31. // used by StringSourceStream; it must not be modified while the
  32. // StringSourceStream exists.
  33. class StringSourceStream : public net::SourceStream {
  34. public:
  35. explicit StringSourceStream(const std::string& src)
  36. : SourceStream(TYPE_UNKNOWN), src_(src) {}
  37. // This source always reads sychronously, so never uses the callback.
  38. int Read(net::IOBuffer* dest_buffer,
  39. int buffer_size,
  40. net::CompletionOnceCallback) override {
  41. if (buffer_size < 0)
  42. return net::ERR_INVALID_ARGUMENT;
  43. if (!MayHaveMoreBytes())
  44. return net::OK;
  45. const size_t read_size =
  46. std::min(src_.size() - read_ofs_, static_cast<size_t>(buffer_size));
  47. memcpy(dest_buffer->data(), src_.data() + read_ofs_, read_size);
  48. read_ofs_ += read_size;
  49. return read_size;
  50. }
  51. std::string Description() const override { return ""; }
  52. bool MayHaveMoreBytes() const override { return read_ofs_ < src_.size(); }
  53. private:
  54. size_t read_ofs_ = 0;
  55. const std::string& src_;
  56. };
  57. class PpdLineReaderImpl : public PpdLineReader {
  58. public:
  59. PpdLineReaderImpl(const std::string& ppd_contents, size_t max_line_length)
  60. : max_line_length_(max_line_length),
  61. read_buf_(base::MakeRefCounted<net::IOBuffer>(kReadBufCapacity)) {
  62. input_ = std::make_unique<StringSourceStream>(ppd_contents);
  63. if (IsGZipped(ppd_contents)) {
  64. input_ = net::GzipSourceStream::Create(std::move(input_),
  65. net::SourceStream::TYPE_GZIP);
  66. }
  67. }
  68. ~PpdLineReaderImpl() override = default;
  69. bool NextLine(std::string* line) override {
  70. line->reserve(max_line_length_);
  71. // Outer loop controls retries; if we fail to read a line, we'll try again
  72. // after the next newline.
  73. while (true) {
  74. line->clear();
  75. while (line->size() <= max_line_length_) {
  76. char c = NextChar();
  77. if (Eof()) {
  78. return !line->empty();
  79. } else if (IsNewline(c)) {
  80. return true;
  81. }
  82. line->push_back(c);
  83. }
  84. // Exceeded max line length, skip the rest of this line, try for another
  85. // one.
  86. if (!SkipToNextLine()) {
  87. return false;
  88. }
  89. }
  90. }
  91. bool Error() const override { return error_; }
  92. private:
  93. // Chunk size of reads to the underlying source stream.
  94. static constexpr int kReadBufCapacity = 500;
  95. // Skip input until we hit a newline (which is discarded). If
  96. // we encounter eof before a newline, false is returned.
  97. bool SkipToNextLine() {
  98. while (true) {
  99. char c = NextChar();
  100. if (Eof()) {
  101. return false;
  102. }
  103. if (IsNewline(c)) {
  104. return true;
  105. }
  106. }
  107. }
  108. // Consume and return the next char from the source stream. If there is no
  109. // more data to be had, set eof. Eof() should be checked before the returned
  110. // value is used.
  111. char NextChar() {
  112. if (read_ofs_ == read_buf_size_) {
  113. // Grab more data from the underlying stream.
  114. read_ofs_ = 0;
  115. // Since StringSourceStream never uses the callback, and filter streams
  116. // are only supposed to use the callback if the underlying source stream
  117. // uses it, we should never see the callback used.
  118. int result = input_->Read(
  119. read_buf_.get(), kReadBufCapacity,
  120. base::BindOnce([](int) { LOG(FATAL) << "Unexpected async read"; }));
  121. if (result == 0) {
  122. eof_ = true;
  123. return '\0';
  124. } else if (result < 0) {
  125. eof_ = true;
  126. error_ = true;
  127. }
  128. read_buf_size_ = result;
  129. }
  130. return read_buf_->data()[read_ofs_++];
  131. }
  132. bool Eof() const { return eof_; }
  133. // Maximum allowable line length from the source. Any lines longer than this
  134. // will be silently discarded.
  135. size_t max_line_length_;
  136. // Buffer for reading from the source stream.
  137. scoped_refptr<net::IOBuffer> read_buf_;
  138. // Number of bytes actually in the buffer.
  139. int read_buf_size_ = 0;
  140. // Offset into read_buf for the next char.
  141. int read_ofs_ = 0;
  142. // Have we hit the end of the source stream?
  143. bool eof_ = false;
  144. // Did we encounter an error while reading?
  145. bool error_ = false;
  146. // The input stream we're reading bytes from. This may be a gzip source
  147. // stream or string source stream depending on the source data.
  148. std::unique_ptr<net::SourceStream> input_;
  149. };
  150. constexpr int PpdLineReaderImpl::kReadBufCapacity;
  151. } // namespace
  152. // static
  153. std::unique_ptr<PpdLineReader> PpdLineReader::Create(
  154. const std::string& contents,
  155. size_t max_line_length) {
  156. return std::make_unique<PpdLineReaderImpl>(contents, max_line_length);
  157. }
  158. // static
  159. bool PpdLineReader::ContainsMagicNumber(const std::string& contents,
  160. size_t max_line_length) {
  161. auto line_reader = PpdLineReader::Create(contents, max_line_length);
  162. std::string line;
  163. return line_reader->NextLine(&line) &&
  164. base::StartsWith(line, kPPDMagicNumberString,
  165. base::CompareCase::SENSITIVE);
  166. }
  167. } // namespace chromeos