summaryrefslogtreecommitdiffstats
path: root/netwerk/base/nsBaseContentStream.h
blob: 13a3766857c4cc5b700bbfff2cfc2fc1b9576a1f (plain)
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
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef nsBaseContentStream_h__
#define nsBaseContentStream_h__

#include "nsIAsyncInputStream.h"
#include "nsIEventTarget.h"
#include "nsCOMPtr.h"

//-----------------------------------------------------------------------------
// nsBaseContentStream is designed to be subclassed with the intention of being
// used to satisfy the nsBaseChannel::OpenContentStream method.
//
// The subclass typically overrides the default Available, ReadSegments and
// CloseWithStatus methods.  By default, Read is implemented in terms of
// ReadSegments, and Close is implemented in terms of CloseWithStatus.  If
// CloseWithStatus is overriden, then the subclass will usually want to call
// the base class' CloseWithStatus method before returning.
//
// If the stream is non-blocking, then readSegments may return the exception
// NS_BASE_STREAM_WOULD_BLOCK if there is no data available and the stream is
// not at the "end-of-file" or already closed.  This error code must not be
// returned from the Available implementation.  When the caller receives this
// error code, he may choose to call the stream's AsyncWait method, in which
// case the base stream will have a non-null PendingCallback.  When the stream
// has data or encounters an error, it should be sure to dispatch a pending
// callback if one exists (see DispatchCallback).  The implementation of the
// base stream's CloseWithStatus (and Close) method will ensure that any
// pending callback is dispatched.  It is the responsibility of the subclass
// to ensure that the pending callback is dispatched when it wants to have its
// ReadSegments method called again.

class nsBaseContentStream : public nsIAsyncInputStream {
 public:
  NS_DECL_THREADSAFE_ISUPPORTS
  NS_DECL_NSIINPUTSTREAM
  NS_DECL_NSIASYNCINPUTSTREAM

  explicit nsBaseContentStream(bool nonBlocking)
      : mStatus(NS_OK), mNonBlocking(nonBlocking) {}

  nsresult Status() { return mStatus; }
  bool IsNonBlocking() { return mNonBlocking; }
  bool IsClosed() { return NS_FAILED(mStatus); }

  // Called to test if the stream has a pending callback.
  bool HasPendingCallback() { return mCallback != nullptr; }

  // The current dispatch target (may be null) for the pending callback if any.
  nsIEventTarget* CallbackTarget() { return mCallbackTarget; }

  // Called to dispatch a pending callback.  If there is no pending callback,
  // then this function does nothing.  Pass true to this function to cause the
  // callback to occur asynchronously; otherwise, the callback will happen
  // before this function returns.
  void DispatchCallback(bool async = true);

  // Helper function to make code more self-documenting.
  void DispatchCallbackSync() { DispatchCallback(false); }

 protected:
  virtual ~nsBaseContentStream() = default;

 private:
  // Called from the base stream's AsyncWait method when a pending callback
  // is installed on the stream.
  virtual void OnCallbackPending() {}

 private:
  nsCOMPtr<nsIInputStreamCallback> mCallback;
  nsCOMPtr<nsIEventTarget> mCallbackTarget;
  nsresult mStatus;
  bool mNonBlocking;
};

#endif  // nsBaseContentStream_h__