summaryrefslogtreecommitdiffstats
path: root/netwerk/protocol/res/SubstitutingProtocolHandler.h
blob: 57bce8c7fef5f980cc55e93ce675c9fea8b8762b (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
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
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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 SubstitutingProtocolHandler_h___
#define SubstitutingProtocolHandler_h___

#include "nsISubstitutingProtocolHandler.h"

#include "nsDataHashtable.h"
#include "nsStandardURL.h"
#include "nsJARURI.h"
#include "mozilla/chrome/RegistryMessageUtils.h"
#include "mozilla/Maybe.h"
#include "mozilla/RWLock.h"

class nsIIOService;

namespace mozilla {
namespace net {

//
// Base class for resource://-like substitution protocols.
//
// If you add a new protocol, make sure to change nsChromeRegistryChrome
// to properly invoke CollectSubstitutions at the right time.
class SubstitutingProtocolHandler {
 public:
  SubstitutingProtocolHandler(const char* aScheme, uint32_t aFlags,
                              bool aEnforceFileOrJar = true);
  explicit SubstitutingProtocolHandler(const char* aScheme);

  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(SubstitutingProtocolHandler);
  NS_DECL_NON_VIRTUAL_NSIPROTOCOLHANDLER;
  NS_DECL_NON_VIRTUAL_NSISUBSTITUTINGPROTOCOLHANDLER;

  bool HasSubstitution(const nsACString& aRoot) const {
    AutoReadLock lock(const_cast<RWLock&>(mSubstitutionsLock));
    return mSubstitutions.Get(aRoot, nullptr);
  }

  nsresult NewURI(const nsACString& aSpec, const char* aCharset,
                  nsIURI* aBaseURI, nsIURI** aResult);

  [[nodiscard]] nsresult CollectSubstitutions(
      nsTArray<SubstitutionMapping>& aResources);

 protected:
  virtual ~SubstitutingProtocolHandler() = default;
  void ConstructInternal();

  [[nodiscard]] nsresult SendSubstitution(const nsACString& aRoot,
                                          nsIURI* aBaseURI, uint32_t aFlags);

  nsresult GetSubstitutionFlags(const nsACString& root, uint32_t* flags);

  // Override this in the subclass to try additional lookups after checking
  // mSubstitutions.
  [[nodiscard]] virtual nsresult GetSubstitutionInternal(
      const nsACString& aRoot, nsIURI** aResult, uint32_t* aFlags) {
    *aResult = nullptr;
    *aFlags = 0;
    return NS_ERROR_NOT_AVAILABLE;
  }

  // Override this in the subclass to check for special case when resolving URIs
  // _before_ checking substitutions.
  [[nodiscard]] virtual bool ResolveSpecialCases(const nsACString& aHost,
                                                 const nsACString& aPath,
                                                 const nsACString& aPathname,
                                                 nsACString& aResult) {
    return false;
  }

  // This method should only return true if GetSubstitutionInternal would
  // return the RESOLVE_JAR_URI flag.
  [[nodiscard]] virtual bool MustResolveJAR(const nsACString& aRoot) {
    return false;
  }

  // Override this in the subclass to check for special case when opening
  // channels.
  [[nodiscard]] virtual nsresult SubstituteChannel(nsIURI* uri,
                                                   nsILoadInfo* aLoadInfo,
                                                   nsIChannel** result) {
    return NS_OK;
  }

  nsIIOService* IOService() { return mIOService; }

 private:
  struct SubstitutionEntry {
    SubstitutionEntry() : flags(0) {}

    ~SubstitutionEntry() = default;

    nsCOMPtr<nsIURI> baseURI;
    uint32_t flags;
  };

  // Notifies all observers that a new substitution from |aRoot| to
  // |aBaseURI| has been set/installed for this protocol handler.
  void NotifyObservers(const nsACString& aRoot, nsIURI* aBaseURI);

  nsCString mScheme;
  Maybe<uint32_t> mFlags;

  RWLock mSubstitutionsLock;
  nsDataHashtable<nsCStringHashKey, SubstitutionEntry> mSubstitutions;
  nsCOMPtr<nsIIOService> mIOService;

  // Returns a SubstitutingJARURI if |aUrl| maps to a |jar:| URI,
  // otherwise will return |aURL|
  nsresult ResolveJARURI(nsIURL* aURL, nsIURI** aResult);

  // In general, we expect the principal of a document loaded from a
  // substituting URI to be a content principal for that URI (rather than
  // a principal for whatever is underneath). However, this only works if
  // the protocol handler for the underlying URI doesn't set an explicit
  // owner (which chrome:// does, for example). So we want to require that
  // substituting URIs only map to other URIs of the same type, or to
  // file:// and jar:// URIs.
  //
  // Enforcing this for ye olde resource:// URIs could carry compat risks, so
  // we just try to enforce it on new protocols going forward.
  bool mEnforceFileOrJar;
};

}  // namespace net
}  // namespace mozilla

#endif /* SubstitutingProtocolHandler_h___ */