1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
  134
  135
  136
  137

content / renderer / mhtml_handle_writer.h [blame]

// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CONTENT_RENDERER_MHTML_HANDLE_WRITER_H_
#define CONTENT_RENDERER_MHTML_HANDLE_WRITER_H_

#include <memory>
#include <vector>

#include "base/files/file.h"
#include "base/functional/callback.h"
#include "base/time/time.h"
#include "content/common/download/mhtml_file_writer.mojom-forward.h"
#include "mojo/public/cpp/system/data_pipe.h"

namespace base {
class TaskRunner;
}

namespace blink {
class WebThreadSafeData;
}

namespace mojo {
class SimpleWatcher;
}

namespace content {

// TODO(crbug.com/40606905): This class needs unit tests.

// Handle wrapper for MHTML serialization to abstract the handle which data
// is written to. This is instantiated on the heap and is responsible for
// destroying itself after completing its write operation.
// Should only live in blocking sequenced threads.
class MHTMLHandleWriter {
 public:
  using MHTMLWriteCompleteCallback =
      base::OnceCallback<void(mojom::MhtmlSaveStatus)>;

  MHTMLHandleWriter(scoped_refptr<base::TaskRunner> main_thread_task_runner,
                    MHTMLWriteCompleteCallback callback);

  MHTMLHandleWriter(const MHTMLHandleWriter&) = delete;
  MHTMLHandleWriter& operator=(const MHTMLHandleWriter&) = delete;

  virtual ~MHTMLHandleWriter();

  void WriteContents(std::vector<blink::WebThreadSafeData> mhtml_contents);

  // Finalizes the writing operation, recording the UMA, closing the handle,
  // and deleting itself.
  void Finish(mojom::MhtmlSaveStatus save_status);

 protected:
  virtual void WriteContentsImpl(
      std::vector<blink::WebThreadSafeData> mhtml_contents) = 0;

  virtual void Close() = 0;

 private:
  scoped_refptr<base::TaskRunner> main_thread_task_runner_;
  MHTMLWriteCompleteCallback callback_;
  bool is_writing_ = false;
};

// Wraps a base::File target to write MHTML contents to.
// This implementation immediately finishes after writing all MHTML contents
// to the file handle.
class MHTMLFileHandleWriter : public MHTMLHandleWriter {
 public:
  MHTMLFileHandleWriter(scoped_refptr<base::TaskRunner> main_thread_task_runner,
                        MHTMLWriteCompleteCallback callback,
                        base::File file);

  MHTMLFileHandleWriter(const MHTMLFileHandleWriter&) = delete;
  MHTMLFileHandleWriter& operator=(const MHTMLFileHandleWriter&) = delete;

  ~MHTMLFileHandleWriter() override;

 protected:
  // Writes the serialized and encoded MHTML data from WebThreadSafeData
  // instances directly to the file handle passed from the Browser.
  void WriteContentsImpl(
      std::vector<blink::WebThreadSafeData> mhtml_contents) override;

  void Close() override;

 private:
  base::File file_;
};

// Wraps a mojo::ScopedDataPipeProducerHandle target to write MHTML contents to.
// This implementation does not immediately finish and destroy itself due to
// the limited size of the data pipe buffer. We must ensure all data is
// written to the handle before finishing the write operation.
class MHTMLProducerHandleWriter : public MHTMLHandleWriter {
 public:
  MHTMLProducerHandleWriter(
      scoped_refptr<base::TaskRunner> main_thread_task_runner,
      MHTMLWriteCompleteCallback callback,
      mojo::ScopedDataPipeProducerHandle producer);

  MHTMLProducerHandleWriter(const MHTMLProducerHandleWriter&) = delete;
  MHTMLProducerHandleWriter& operator=(const MHTMLProducerHandleWriter&) =
      delete;

  ~MHTMLProducerHandleWriter() override;

 protected:
  // Creates a new SequencedTaskRunner to dispatch |watcher_| invocations on.
  void WriteContentsImpl(
      std::vector<blink::WebThreadSafeData> mhtml_contents) override;

  void Close() override;

 private:
  void BeginWatchingHandle();

  // Writes the serialized and encoded MHTML data from WebThreadSafeData
  // instances to producer while possible.
  void TryWritingContents(MojoResult result,
                          const mojo::HandleSignalsState& state);

  mojo::ScopedDataPipeProducerHandle producer_;

  std::vector<blink::WebThreadSafeData> mhtml_contents_;
  std::unique_ptr<mojo::SimpleWatcher> watcher_;

  size_t current_block_;
  size_t write_position_;
};

}  // namespace content

#endif  // CONTENT_RENDERER_MHTML_HANDLE_WRITER_H_