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/filter/fuzzed_source_stream.h"
6 
7 #include <fuzzer/FuzzedDataProvider.h>
8 
9 #include <algorithm>
10 #include <string>
11 #include <utility>
12 
13 #include "base/bind.h"
14 #include "base/threading/thread_task_runner_handle.h"
15 #include "net/base/io_buffer.h"
16 #include "net/base/net_errors.h"
17 
18 namespace net {
19 
20 namespace {
21 
22 // Common net error codes that can be returned by a SourceStream.
23 const Error kReadErrors[] = {OK, ERR_FAILED, ERR_CONTENT_DECODING_FAILED};
24 
25 }  // namespace
26 
FuzzedSourceStream(FuzzedDataProvider * data_provider)27 FuzzedSourceStream::FuzzedSourceStream(FuzzedDataProvider* data_provider)
28     : SourceStream(SourceStream::TYPE_NONE),
29       data_provider_(data_provider),
30       read_pending_(false),
31       end_returned_(false) {}
32 
~FuzzedSourceStream()33 FuzzedSourceStream::~FuzzedSourceStream() {
34   DCHECK(!read_pending_);
35 }
36 
Read(IOBuffer * buf,int buf_len,CompletionOnceCallback callback)37 int FuzzedSourceStream::Read(IOBuffer* buf,
38                              int buf_len,
39                              CompletionOnceCallback callback) {
40   DCHECK(!read_pending_);
41   DCHECK(!end_returned_);
42   DCHECK_LE(0, buf_len);
43 
44   bool sync = data_provider_->ConsumeBool();
45   int result = data_provider_->ConsumeIntegralInRange(0, buf_len);
46   std::string data = data_provider_->ConsumeBytesAsString(result);
47   result = data.size();
48 
49   if (result <= 0)
50     result = data_provider_->PickValueInArray(kReadErrors);
51 
52   if (sync) {
53     if (result > 0) {
54       std::copy(data.data(), data.data() + data.size(), buf->data());
55     } else {
56       end_returned_ = true;
57     }
58     return result;
59   }
60 
61   scoped_refptr<IOBuffer> pending_read_buf = buf;
62 
63   read_pending_ = true;
64   // |this| is owned by the caller so use base::Unretained is safe.
65   base::ThreadTaskRunnerHandle::Get()->PostTask(
66       FROM_HERE, base::BindOnce(&FuzzedSourceStream::OnReadComplete,
67                                 base::Unretained(this), std::move(callback),
68                                 data, pending_read_buf, result));
69   return ERR_IO_PENDING;
70 }
71 
Description() const72 std::string FuzzedSourceStream::Description() const {
73   return "";
74 }
75 
MayHaveMoreBytes() const76 bool FuzzedSourceStream::MayHaveMoreBytes() const {
77   return !end_returned_;
78 }
79 
OnReadComplete(CompletionOnceCallback callback,const std::string & fuzzed_data,scoped_refptr<IOBuffer> read_buf,int result)80 void FuzzedSourceStream::OnReadComplete(CompletionOnceCallback callback,
81                                         const std::string& fuzzed_data,
82                                         scoped_refptr<IOBuffer> read_buf,
83                                         int result) {
84   DCHECK(read_pending_);
85 
86   if (result > 0) {
87     std::copy(fuzzed_data.data(), fuzzed_data.data() + result,
88               read_buf->data());
89   } else {
90     end_returned_ = true;
91   }
92   read_pending_ = false;
93   std::move(callback).Run(result);
94 }
95 
96 }  // namespace net
97