Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/netwerk/protocol/http/HttpAuthUtils.cpp
Line
Count
Source (jump to first uncovered line)
1
/* This Source Code Form is subject to the terms of the Mozilla Public
2
 * License, v. 2.0. If a copy of the MPL was not distributed with this
3
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5
#include "mozilla/net/HttpAuthUtils.h"
6
#include "mozilla/Tokenizer.h"
7
#include "nsIPrefService.h"
8
#include "nsIURI.h"
9
#include "nsNetUtil.h"
10
#include "nsUnicharUtils.h"
11
12
namespace mozilla {
13
namespace net {
14
namespace auth {
15
16
namespace detail {
17
18
bool
19
MatchesBaseURI(const nsACString& matchScheme,
20
               const nsACString& matchHost,
21
               int32_t             matchPort,
22
               nsDependentCSubstring const& url)
23
0
{
24
0
  // check if scheme://host:port matches baseURI
25
0
26
0
  // parse the base URI
27
0
  mozilla::Tokenizer t(url);
28
0
  mozilla::Tokenizer::Token token;
29
0
30
0
  t.SkipWhites();
31
0
32
0
  // We don't know if the url to check against starts with scheme
33
0
  // or a host name.  Start recording here.
34
0
  t.Record();
35
0
36
0
  mozilla::Unused << t.Next(token);
37
0
38
0
  // The ipv6 literals MUST be enclosed with [] in the preference.
39
0
  bool ipv6 = false;
40
0
  if (token.Equals(mozilla::Tokenizer::Token::Char('['))) {
41
0
    nsDependentCSubstring ipv6BareLiteral;
42
0
    if (!t.ReadUntil(mozilla::Tokenizer::Token::Char(']'), ipv6BareLiteral)) {
43
0
      // Broken ipv6 literal
44
0
      return false;
45
0
    }
46
0
47
0
    nsDependentCSubstring ipv6Literal;
48
0
    t.Claim(ipv6Literal, mozilla::Tokenizer::INCLUDE_LAST);
49
0
    if (!matchHost.Equals(ipv6Literal, nsCaseInsensitiveUTF8StringComparator()) &&
50
0
        !matchHost.Equals(ipv6BareLiteral, nsCaseInsensitiveUTF8StringComparator())) {
51
0
      return false;
52
0
    }
53
0
54
0
    ipv6 = true;
55
0
  } else if (t.CheckChar(':') && t.CheckChar('/') && t.CheckChar('/')) {
56
0
    if (!matchScheme.Equals(token.Fragment())) {
57
0
      return false;
58
0
    }
59
0
    // Re-start recording the hostname from the point after scheme://.
60
0
    t.Record();
61
0
  }
62
0
63
0
  while (t.Next(token)) {
64
0
    bool eof = token.Equals(mozilla::Tokenizer::Token::EndOfFile());
65
0
    bool port = token.Equals(mozilla::Tokenizer::Token::Char(':'));
66
0
67
0
    if (eof || port) {
68
0
      if (!ipv6) { // Match already performed above.
69
0
        nsDependentCSubstring hostName;
70
0
        t.Claim(hostName);
71
0
72
0
        // An empty hostname means to accept everything for the schema
73
0
        if (!hostName.IsEmpty()) {
74
0
          /*
75
0
           host:      bar.com   foo.bar.com   foobar.com  foo.bar.com    bar.com
76
0
           pref:      bar.com       bar.com      bar.com     .bar.com   .bar.com
77
0
           result:     accept        accept       reject       accept     reject
78
0
          */
79
0
          if (!StringEndsWith(matchHost, hostName, nsCaseInsensitiveUTF8StringComparator())) {
80
0
            return false;
81
0
          }
82
0
          if (matchHost.Length() > hostName.Length() &&
83
0
              matchHost[matchHost.Length() - hostName.Length() - 1] != '.' &&
84
0
              hostName[0] != '.') {
85
0
            return false;
86
0
          }
87
0
        }
88
0
      }
89
0
90
0
      if (port) {
91
0
        uint16_t portNumber;
92
0
        if (!t.ReadInteger(&portNumber)) {
93
0
          // Missing port number
94
0
          return false;
95
0
        }
96
0
        if (matchPort != portNumber) {
97
0
          return false;
98
0
        }
99
0
        if (!t.CheckEOF()) {
100
0
          return false;
101
0
        }
102
0
      }
103
0
    } else if (ipv6) {
104
0
      // After an ipv6 literal there can only be EOF or :port.  Everything else
105
0
      // must be treated as non-match/broken input.
106
0
      return false;
107
0
    }
108
0
  }
109
0
110
0
  // All negative checks has passed positively.
111
0
  return true;
112
0
}
113
114
} // namespace detail
115
116
117
bool
118
URIMatchesPrefPattern(nsIURI *uri, const char *pref)
119
0
{
120
0
  nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
121
0
  if (!prefs) {
122
0
    return false;
123
0
  }
124
0
125
0
  nsAutoCString scheme, host;
126
0
  int32_t port;
127
0
128
0
  if (NS_FAILED(uri->GetScheme(scheme))) {
129
0
    return false;
130
0
  }
131
0
  if (NS_FAILED(uri->GetAsciiHost(host))) {
132
0
    return false;
133
0
  }
134
0
135
0
  port = NS_GetRealPort(uri);
136
0
  if (port == -1) {
137
0
    return false;
138
0
  }
139
0
140
0
  nsAutoCString hostList;
141
0
  if (NS_FAILED(prefs->GetCharPref(pref, hostList))) {
142
0
    return false;
143
0
  }
144
0
145
0
  // pseudo-BNF
146
0
  // ----------
147
0
  //
148
0
  // url-list       base-url ( base-url "," LWS )*
149
0
  // base-url       ( scheme-part | host-part | scheme-part host-part )
150
0
  // scheme-part    scheme "://"
151
0
  // host-part      host [":" port]
152
0
  //
153
0
  // for example:
154
0
  //   "https://, http://office.foo.com"
155
0
  //
156
0
157
0
  mozilla::Tokenizer t(hostList);
158
0
  while (!t.CheckEOF()) {
159
0
    t.SkipWhites();
160
0
    nsDependentCSubstring url;
161
0
    mozilla::Unused << t.ReadUntil(mozilla::Tokenizer::Token::Char(','), url);
162
0
    if (url.IsEmpty()) {
163
0
      continue;
164
0
    }
165
0
    if (detail::MatchesBaseURI(scheme, host, port, url)) {
166
0
      return true;
167
0
    }
168
0
  }
169
0
170
0
  return false;
171
0
}
172
173
} // namespace auth
174
} // namespace net
175
} // namespace mozilla