Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/netwerk/base/nsProtocolProxyService.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
/* vim:set ts=4 sw=4 sts=4 et: */
3
/* This Source Code Form is subject to the terms of the Mozilla Public
4
 * License, v. 2.0. If a copy of the MPL was not distributed with this
5
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7
#include "mozilla/ArrayUtils.h"
8
#include "mozilla/Attributes.h"
9
#include "mozilla/AutoRestore.h"
10
11
#include "nsProtocolProxyService.h"
12
#include "nsProxyInfo.h"
13
#include "nsIClassInfoImpl.h"
14
#include "nsIIOService.h"
15
#include "nsIObserverService.h"
16
#include "nsIProtocolHandler.h"
17
#include "nsIProtocolProxyCallback.h"
18
#include "nsIChannel.h"
19
#include "nsICancelable.h"
20
#include "nsIDNSService.h"
21
#include "nsPIDNSService.h"
22
#include "nsIScriptSecurityManager.h"
23
#include "nsIPrefService.h"
24
#include "nsIPrefBranch.h"
25
#include "nsContentUtils.h"
26
#include "nsThreadUtils.h"
27
#include "nsQueryObject.h"
28
#include "nsSOCKSIOLayer.h"
29
#include "nsString.h"
30
#include "nsNetUtil.h"
31
#include "nsNetCID.h"
32
#include "plstr.h"
33
#include "prnetdb.h"
34
#include "nsPACMan.h"
35
#include "nsProxyRelease.h"
36
#include "mozilla/Mutex.h"
37
#include "mozilla/CondVar.h"
38
#include "nsISystemProxySettings.h"
39
#include "nsINetworkLinkService.h"
40
#include "nsIHttpChannelInternal.h"
41
#include "mozilla/Logging.h"
42
#include "mozilla/Tokenizer.h"
43
#include "mozilla/Unused.h"
44
45
//----------------------------------------------------------------------------
46
47
namespace mozilla {
48
namespace net {
49
50
  extern const char kProxyType_HTTP[];
51
  extern const char kProxyType_HTTPS[];
52
  extern const char kProxyType_SOCKS[];
53
  extern const char kProxyType_SOCKS4[];
54
  extern const char kProxyType_SOCKS5[];
55
  extern const char kProxyType_DIRECT[];
56
57
#undef LOG
58
0
#define LOG(args) MOZ_LOG(gProxyLog, LogLevel::Debug, args)
59
60
//----------------------------------------------------------------------------
61
62
0
#define PROXY_PREF_BRANCH  "network.proxy"
63
0
#define PROXY_PREF(x)      PROXY_PREF_BRANCH "." x
64
65
66
//----------------------------------------------------------------------------
67
68
// This structure is intended to be allocated on the stack
69
struct nsProtocolInfo {
70
    nsAutoCString scheme;
71
    uint32_t flags;
72
    int32_t defaultPort;
73
};
74
75
//----------------------------------------------------------------------------
76
77
// Return the channel's proxy URI, or if it doesn't exist, the
78
// channel's main URI.
79
static nsresult
80
GetProxyURI(nsIChannel *channel, nsIURI **aOut)
81
0
{
82
0
  nsresult rv = NS_OK;
83
0
  nsCOMPtr<nsIURI> proxyURI;
84
0
  nsCOMPtr<nsIHttpChannelInternal> httpChannel(do_QueryInterface(channel));
85
0
  if (httpChannel) {
86
0
    rv = httpChannel->GetProxyURI(getter_AddRefs(proxyURI));
87
0
  }
88
0
  if (!proxyURI) {
89
0
    rv = channel->GetURI(getter_AddRefs(proxyURI));
90
0
  }
91
0
  if (NS_FAILED(rv)) {
92
0
    return rv;
93
0
  }
94
0
  proxyURI.forget(aOut);
95
0
  return NS_OK;
96
0
}
97
98
//-----------------------------------------------------------------------------
99
100
nsProtocolProxyService::FilterLink::FilterLink(uint32_t p,
101
                                               nsIProtocolProxyFilter *f)
102
  : position(p), filter(f), channelFilter(nullptr)
103
0
{
104
0
  LOG(("nsProtocolProxyService::FilterLink::FilterLink %p, filter=%p", this, f));
105
0
}
106
nsProtocolProxyService::FilterLink::FilterLink(uint32_t p,
107
                                               nsIProtocolProxyChannelFilter *cf)
108
  : position(p), filter(nullptr), channelFilter(cf)
109
0
{
110
0
  LOG(("nsProtocolProxyService::FilterLink::FilterLink %p, channel-filter=%p", this, cf));
111
0
}
112
113
nsProtocolProxyService::FilterLink::~FilterLink()
114
0
{
115
0
  LOG(("nsProtocolProxyService::FilterLink::~FilterLink %p", this));
116
0
}
117
118
//-----------------------------------------------------------------------------
119
120
// The nsPACManCallback portion of this implementation should be run
121
// on the main thread - so call nsPACMan::AsyncGetProxyForURI() with
122
// a true mainThreadResponse parameter.
123
class nsAsyncResolveRequest final : public nsIRunnable
124
                                  , public nsPACManCallback
125
                                  , public nsICancelable
126
{
127
public:
128
    NS_DECL_THREADSAFE_ISUPPORTS
129
130
    nsAsyncResolveRequest(nsProtocolProxyService *pps, nsIChannel *channel,
131
                          uint32_t aResolveFlags,
132
                          nsIProtocolProxyCallback *callback)
133
        : mStatus(NS_OK)
134
        , mDispatched(false)
135
        , mResolveFlags(aResolveFlags)
136
        , mPPS(pps)
137
        , mXPComPPS(pps)
138
        , mChannel(channel)
139
        , mCallback(callback)
140
0
    {
141
0
        NS_ASSERTION(mCallback, "null callback");
142
0
    }
143
144
private:
145
    ~nsAsyncResolveRequest()
146
0
    {
147
0
        if (!NS_IsMainThread()) {
148
0
            // these xpcom pointers might need to be proxied back to the
149
0
            // main thread to delete safely, but if this request had its
150
0
            // callbacks called normally they will all be null and this is a nop
151
0
152
0
            if (mChannel) {
153
0
                NS_ReleaseOnMainThreadSystemGroup(
154
0
                  "nsAsyncResolveRequest::mChannel", mChannel.forget());
155
0
            }
156
0
157
0
            if (mCallback) {
158
0
                NS_ReleaseOnMainThreadSystemGroup(
159
0
                  "nsAsyncResolveRequest::mCallback", mCallback.forget());
160
0
            }
161
0
162
0
            if (mProxyInfo) {
163
0
                NS_ReleaseOnMainThreadSystemGroup(
164
0
                  "nsAsyncResolveRequest::mProxyInfo", mProxyInfo.forget());
165
0
            }
166
0
167
0
            if (mXPComPPS) {
168
0
                NS_ReleaseOnMainThreadSystemGroup(
169
0
                  "nsAsyncResolveRequest::mXPComPPS", mXPComPPS.forget());
170
0
            }
171
0
        }
172
0
    }
173
174
    // Helper class to loop over all registered asynchronous filters.
175
    // There is a cycle between nsAsyncResolveRequest and this class that
176
    // is broken after the last filter has called back on this object.
177
    class AsyncApplyFilters final
178
      : public nsIProxyProtocolFilterResult
179
      , public nsIRunnable
180
      , public nsICancelable
181
    {
182
      // The reference counter is thread-safe, but the processing logic is
183
      // considered single thread only.  We want the counter be thread safe,
184
      // since this class can be released on a background thread.
185
      NS_DECL_THREADSAFE_ISUPPORTS
186
      NS_DECL_NSIPROXYPROTOCOLFILTERRESULT
187
      NS_DECL_NSIRUNNABLE
188
      NS_DECL_NSICANCELABLE
189
190
      typedef std::function<nsresult(nsAsyncResolveRequest*, nsIProxyInfo*, bool)> Callback;
191
192
      explicit AsyncApplyFilters(nsProtocolInfo& aInfo, Callback const& aCallback);
193
      // This method starts the processing or filters.  If all of them
194
      // answer synchronously (call back from within applyFilters) this method
195
      // will return immediately and the returning result will carry return
196
      // result of the callback given in constructor.
197
      // This method is looping the registered filters (that have been copied
198
      // locally) as long as an answer from a filter is obtained synchronously.
199
      // Note that filters are processed serially to let them build a list
200
      // of proxy info.
201
      nsresult AsyncProcess(nsAsyncResolveRequest* aRequest);
202
203
    private:
204
      typedef nsProtocolProxyService::FilterLink FilterLink;
205
206
      virtual ~AsyncApplyFilters();
207
      // Processes the next filter and loops until a filter is successfully
208
      // called on or it has called back to us.
209
      nsresult ProcessNextFilter();
210
      // Called after the last filter has been processed (=called back or failed to
211
      // be called on)
212
      nsresult Finish();
213
214
      nsProtocolInfo mInfo;
215
      // This is nullified before we call back on the request or when
216
      // Cancel() on this object has been called to break the cycle
217
      // and signal to stop.
218
      RefPtr<nsAsyncResolveRequest> mRequest;
219
      Callback mCallback;
220
      // A shallow snapshot of filters as they were registered at the moment
221
      // we started to process filters for the given resolve request.
222
      nsTArray<RefPtr<FilterLink>> mFiltersCopy;
223
224
      nsTArray<RefPtr<FilterLink>>::index_type mNextFilterIndex;
225
      // true when we are calling ProcessNextFilter() from inside AsyncProcess(),
226
      // false otherwise.
227
      bool mProcessingInLoop;
228
      // true after a filter called back to us with a result, dropped to false
229
      // just before we call a filter.
230
      bool mFilterCalledBack;
231
232
      // This keeps the initial value we pass to the first filter in line and also
233
      // collects the result from each filter call.
234
      nsCOMPtr<nsIProxyInfo> mProxyInfo;
235
236
      // The logic is written as non-thread safe, assert single-thread usage.
237
      nsCOMPtr<nsIEventTarget> mProcessingThread;
238
    };
239
240
public:
241
    nsresult ProcessLocally(nsProtocolInfo &info, nsIProxyInfo* pi, bool isSyncOK)
242
0
    {
243
0
        SetResult(NS_OK, pi);
244
0
245
0
        auto consumeFiltersResult = [isSyncOK]
246
0
                                    (nsAsyncResolveRequest* ctx, nsIProxyInfo* pi, bool aCalledAsync) -> nsresult
247
0
        {
248
0
          ctx->SetResult(NS_OK, pi);
249
0
          if (isSyncOK || aCalledAsync) {
250
0
            ctx->Run();
251
0
            return NS_OK;
252
0
          }
253
0
254
0
          return ctx->DispatchCallback();
255
0
        };
256
0
257
0
        mAsyncFilterApplier = new AsyncApplyFilters(info, consumeFiltersResult);
258
0
        // may call consumeFiltersResult() directly
259
0
        return mAsyncFilterApplier->AsyncProcess(this);
260
0
    }
261
262
    void SetResult(nsresult status, nsIProxyInfo *pi)
263
0
    {
264
0
        mStatus = status;
265
0
        mProxyInfo = pi;
266
0
    }
267
268
    NS_IMETHOD Run() override
269
0
    {
270
0
        if (mCallback)
271
0
            DoCallback();
272
0
        return NS_OK;
273
0
    }
274
275
    NS_IMETHOD Cancel(nsresult reason) override
276
0
    {
277
0
        NS_ENSURE_ARG(NS_FAILED(reason));
278
0
279
0
        if (mAsyncFilterApplier) {
280
0
            mAsyncFilterApplier->Cancel(reason);
281
0
        }
282
0
283
0
        // If we've already called DoCallback then, nothing more to do.
284
0
        if (!mCallback)
285
0
            return NS_OK;
286
0
287
0
        SetResult(reason, nullptr);
288
0
        return DispatchCallback();
289
0
    }
290
291
    nsresult DispatchCallback()
292
0
    {
293
0
        if (mDispatched)  // Only need to dispatch once
294
0
            return NS_OK;
295
0
296
0
        nsresult rv = NS_DispatchToCurrentThread(this);
297
0
        if (NS_FAILED(rv))
298
0
            NS_WARNING("unable to dispatch callback event");
299
0
        else {
300
0
            mDispatched = true;
301
0
            return NS_OK;
302
0
        }
303
0
304
0
        mCallback = nullptr;  // break possible reference cycle
305
0
        return rv;
306
0
    }
307
308
private:
309
310
    // Called asynchronously, so we do not need to post another PLEvent
311
    // before calling DoCallback.
312
    void OnQueryComplete(nsresult status,
313
                         const nsACString &pacString,
314
                         const nsACString &newPACURL) override
315
0
    {
316
0
        // If we've already called DoCallback then, nothing more to do.
317
0
        if (!mCallback)
318
0
            return;
319
0
320
0
        // Provided we haven't been canceled...
321
0
        if (mStatus == NS_OK) {
322
0
            mStatus = status;
323
0
            mPACString = pacString;
324
0
            mPACURL = newPACURL;
325
0
        }
326
0
327
0
        // In the cancelation case, we may still have another PLEvent in
328
0
        // the queue that wants to call DoCallback.  No need to wait for
329
0
        // it, just run the callback now.
330
0
        DoCallback();
331
0
    }
332
333
    void DoCallback()
334
0
    {
335
0
        bool pacAvailable = true;
336
0
        if (mStatus == NS_ERROR_NOT_AVAILABLE && !mProxyInfo) {
337
0
            // If the PAC service is not avail (e.g. failed pac load
338
0
            // or shutdown) then we will be going direct. Make that
339
0
            // mapping now so that any filters are still applied.
340
0
            mPACString = NS_LITERAL_CSTRING("DIRECT;");
341
0
            mStatus = NS_OK;
342
0
343
0
            LOG(("pac not available, use DIRECT\n"));
344
0
            pacAvailable = false;
345
0
        }
346
0
347
0
        // Generate proxy info from the PAC string if appropriate
348
0
        if (NS_SUCCEEDED(mStatus) && !mProxyInfo && !mPACString.IsEmpty()) {
349
0
            mPPS->ProcessPACString(mPACString, mResolveFlags,
350
0
                                   getter_AddRefs(mProxyInfo));
351
0
            nsCOMPtr<nsIURI> proxyURI;
352
0
            GetProxyURI(mChannel, getter_AddRefs(proxyURI));
353
0
354
0
            // Now apply proxy filters
355
0
            nsProtocolInfo info;
356
0
            mStatus = mPPS->GetProtocolInfo(proxyURI, &info);
357
0
358
0
            auto consumeFiltersResult = [pacAvailable]
359
0
                                        (nsAsyncResolveRequest* self, nsIProxyInfo* pi, bool async) -> nsresult
360
0
            {
361
0
                LOG(("DoCallback::consumeFiltersResult this=%p, pi=%p, async=%d",
362
0
                     self, pi, async));
363
0
364
0
                self->mProxyInfo = pi;
365
0
366
0
                if (pacAvailable) {
367
0
                    // if !pacAvailable, it was already logged above
368
0
                    LOG(("pac thread callback %s\n", self->mPACString.get()));
369
0
                }
370
0
371
0
                if (NS_SUCCEEDED(self->mStatus)) {
372
0
                    self->mPPS->MaybeDisableDNSPrefetch(self->mProxyInfo);
373
0
                }
374
0
375
0
                self->mCallback->OnProxyAvailable(self,
376
0
                                                  self->mChannel,
377
0
                                                  self->mProxyInfo,
378
0
                                                  self->mStatus);
379
0
380
0
                return NS_OK;
381
0
            };
382
0
383
0
            if (NS_SUCCEEDED(mStatus)) {
384
0
                mAsyncFilterApplier = new AsyncApplyFilters(info, consumeFiltersResult);
385
0
                // This may call consumeFiltersResult() directly.
386
0
                mAsyncFilterApplier->AsyncProcess(this);
387
0
                return;
388
0
            }
389
0
390
0
            consumeFiltersResult(this, nullptr, false);
391
0
        }
392
0
        else if (NS_SUCCEEDED(mStatus) && !mPACURL.IsEmpty()) {
393
0
            LOG(("pac thread callback indicates new pac file load\n"));
394
0
395
0
            nsCOMPtr<nsIURI> proxyURI;
396
0
            GetProxyURI(mChannel, getter_AddRefs(proxyURI));
397
0
398
0
            // trigger load of new pac url
399
0
            nsresult rv = mPPS->ConfigureFromPAC(mPACURL, false);
400
0
            if (NS_SUCCEEDED(rv)) {
401
0
                // now that the load is triggered, we can resubmit the query
402
0
                RefPtr<nsAsyncResolveRequest> newRequest =
403
0
                    new nsAsyncResolveRequest(mPPS, mChannel, mResolveFlags,
404
0
                                              mCallback);
405
0
                rv = mPPS->mPACMan->AsyncGetProxyForURI(proxyURI,
406
0
                                                        newRequest,
407
0
                                                        true);
408
0
            }
409
0
410
0
            if (NS_FAILED(rv))
411
0
                mCallback->OnProxyAvailable(this, mChannel, nullptr, rv);
412
0
413
0
            // do not call onproxyavailable() in SUCCESS case - the newRequest will
414
0
            // take care of that
415
0
        }
416
0
        else {
417
0
            LOG(("pac thread callback did not provide information %" PRIX32 "\n",
418
0
                 static_cast<uint32_t>(mStatus)));
419
0
            if (NS_SUCCEEDED(mStatus))
420
0
                mPPS->MaybeDisableDNSPrefetch(mProxyInfo);
421
0
            mCallback->OnProxyAvailable(this, mChannel, mProxyInfo, mStatus);
422
0
        }
423
0
424
0
        // We are on the main thread now and don't need these any more so
425
0
        // release them to avoid having to proxy them back to the main thread
426
0
        // in the dtor
427
0
        mCallback = nullptr;  // in case the callback holds an owning ref to us
428
0
        mPPS = nullptr;
429
0
        mXPComPPS = nullptr;
430
0
        mChannel = nullptr;
431
0
        mProxyInfo = nullptr;
432
0
    }
433
434
private:
435
    nsresult  mStatus;
436
    nsCString mPACString;
437
    nsCString mPACURL;
438
    bool      mDispatched;
439
    uint32_t  mResolveFlags;
440
441
    nsProtocolProxyService            *mPPS;
442
    nsCOMPtr<nsIProtocolProxyService>  mXPComPPS;
443
    nsCOMPtr<nsIChannel>               mChannel;
444
    nsCOMPtr<nsIProtocolProxyCallback> mCallback;
445
    nsCOMPtr<nsIProxyInfo>             mProxyInfo;
446
447
    RefPtr<AsyncApplyFilters> mAsyncFilterApplier;
448
};
449
450
NS_IMPL_ISUPPORTS(nsAsyncResolveRequest,
451
                  nsICancelable,
452
                  nsIRunnable)
453
454
NS_IMPL_ISUPPORTS(nsAsyncResolveRequest::AsyncApplyFilters,
455
                  nsIProxyProtocolFilterResult,
456
                  nsICancelable,
457
                  nsIRunnable)
458
459
nsAsyncResolveRequest::AsyncApplyFilters::AsyncApplyFilters(nsProtocolInfo& aInfo,
460
                                                            Callback const& aCallback)
461
  : mInfo(aInfo)
462
  , mCallback(aCallback)
463
  , mNextFilterIndex(0)
464
  , mProcessingInLoop(false)
465
  , mFilterCalledBack(false)
466
0
{
467
0
  LOG(("AsyncApplyFilters %p", this));
468
0
}
469
470
nsAsyncResolveRequest::AsyncApplyFilters::~AsyncApplyFilters()
471
0
{
472
0
  LOG(("~AsyncApplyFilters %p", this));
473
0
474
0
  MOZ_ASSERT(!mRequest);
475
0
  MOZ_ASSERT(!mProxyInfo);
476
0
  MOZ_ASSERT(!mFiltersCopy.Length());
477
0
}
478
479
nsresult
480
nsAsyncResolveRequest::AsyncApplyFilters::AsyncProcess(nsAsyncResolveRequest * aRequest)
481
0
{
482
0
  LOG(("AsyncApplyFilters::AsyncProcess %p for req %p", this, aRequest));
483
0
484
0
  MOZ_ASSERT(!mRequest, "AsyncApplyFilters started more than once!");
485
0
486
0
  if (!(mInfo.flags & nsIProtocolHandler::ALLOWS_PROXY)) {
487
0
    // Calling the callback directly (not via Finish()) since we
488
0
    // don't want to prune.
489
0
    return mCallback(aRequest, aRequest->mProxyInfo, false);
490
0
  }
491
0
492
0
  mProcessingThread = NS_GetCurrentThread();
493
0
494
0
  mRequest = aRequest;
495
0
  mProxyInfo = aRequest->mProxyInfo;
496
0
497
0
  aRequest->mPPS->CopyFilters(mFiltersCopy);
498
0
499
0
  // We want to give filters a chance to process in a single loop to prevent
500
0
  // any current-thread dispatch delays when those are not needed.
501
0
  // This code is rather "loopy" than "recursive" to prevent long stack traces.
502
0
  do {
503
0
    MOZ_ASSERT(!mProcessingInLoop);
504
0
505
0
    mozilla::AutoRestore<bool> restore(mProcessingInLoop);
506
0
    mProcessingInLoop = true;
507
0
508
0
    nsresult rv = ProcessNextFilter();
509
0
    if (NS_FAILED(rv)) {
510
0
      return rv;
511
0
    }
512
0
  } while (mFilterCalledBack);
513
0
514
0
  return NS_OK;
515
0
}
516
517
nsresult
518
nsAsyncResolveRequest::AsyncApplyFilters::ProcessNextFilter()
519
0
{
520
0
  LOG(("AsyncApplyFilters::ProcessNextFilter %p ENTER pi=%p", this, mProxyInfo.get()));
521
0
522
0
  RefPtr<FilterLink> filter;
523
0
  do {
524
0
    mFilterCalledBack = false;
525
0
526
0
    if (!mRequest) {
527
0
      // We got canceled
528
0
      LOG(("  canceled"));
529
0
      return NS_OK; // should we let the consumer know?
530
0
    }
531
0
532
0
    if (mNextFilterIndex == mFiltersCopy.Length()) {
533
0
      return Finish();
534
0
    }
535
0
536
0
    filter = mFiltersCopy[mNextFilterIndex++];
537
0
538
0
    // Loop until a call to a filter succeeded.  Other option is to recurse
539
0
    // but that would waste stack trace when a number of filters gets registered
540
0
    // and all from some reason tend to fail.
541
0
    // The !mFilterCalledBack part of the condition is there to protect us from
542
0
    // calling on another filter when the current one managed to call back and
543
0
    // then threw. We already have the result so take it and use it since
544
0
    // the next filter will be processed by the root loop or a call to
545
0
    // ProcessNextFilter has already been dispatched to this thread.
546
0
    LOG(("  calling filter %p pi=%p", filter.get(), mProxyInfo.get()));
547
0
  } while (!mRequest->mPPS->ApplyFilter(filter, mRequest->mChannel, mInfo, mProxyInfo, this) &&
548
0
           !mFilterCalledBack);
549
0
550
0
  LOG(("AsyncApplyFilters::ProcessNextFilter %p LEAVE pi=%p", this, mProxyInfo.get()));
551
0
  return NS_OK;
552
0
}
553
554
NS_IMETHODIMP
555
nsAsyncResolveRequest::AsyncApplyFilters::OnProxyFilterResult(nsIProxyInfo* aProxyInfo)
556
0
{
557
0
  LOG(("AsyncApplyFilters::OnProxyFilterResult %p pi=%p", this, aProxyInfo));
558
0
559
0
  MOZ_ASSERT(mProcessingThread && mProcessingThread->IsOnCurrentThread());
560
0
  MOZ_ASSERT(!mFilterCalledBack);
561
0
562
0
  if (mFilterCalledBack) {
563
0
    LOG(("  duplicate notification?"));
564
0
    return NS_OK;
565
0
  }
566
0
567
0
  mFilterCalledBack = true;
568
0
  mProxyInfo = aProxyInfo;
569
0
570
0
  if (mProcessingInLoop) {
571
0
    // No need to call/dispatch ProcessNextFilter(), we are in a control
572
0
    // loop that will do this for us and save recursion/dispatching.
573
0
    LOG(("  in a root loop"));
574
0
    return NS_OK;
575
0
  }
576
0
577
0
  if (!mRequest) {
578
0
    // We got canceled
579
0
    LOG(("  canceled"));
580
0
    return NS_OK;
581
0
  }
582
0
583
0
  if (mNextFilterIndex == mFiltersCopy.Length()) {
584
0
    // We are done, all filters have been called on!
585
0
    Finish();
586
0
    return NS_OK;
587
0
  }
588
0
589
0
  // Redispatch, since we don't want long stacks when filters respond synchronously.
590
0
  LOG(("  redispatching"));
591
0
  NS_DispatchToCurrentThread(this);
592
0
  return NS_OK;
593
0
}
594
595
NS_IMETHODIMP
596
nsAsyncResolveRequest::AsyncApplyFilters::Run()
597
0
{
598
0
  LOG(("AsyncApplyFilters::Run %p", this));
599
0
600
0
  MOZ_ASSERT(mProcessingThread && mProcessingThread->IsOnCurrentThread());
601
0
602
0
  ProcessNextFilter();
603
0
  return NS_OK;
604
0
}
605
606
nsresult
607
nsAsyncResolveRequest::AsyncApplyFilters::Finish()
608
0
{
609
0
  LOG(("AsyncApplyFilters::Finish %p pi=%p", this, mProxyInfo.get()));
610
0
611
0
  MOZ_ASSERT(mRequest);
612
0
613
0
  mFiltersCopy.Clear();
614
0
615
0
  RefPtr<nsAsyncResolveRequest> request;
616
0
  request.swap(mRequest);
617
0
618
0
  nsCOMPtr<nsIProxyInfo> pi;
619
0
  pi.swap(mProxyInfo);
620
0
621
0
  request->mPPS->PruneProxyInfo(mInfo, pi);
622
0
  return mCallback(request, pi, !mProcessingInLoop);
623
0
}
624
625
NS_IMETHODIMP
626
nsAsyncResolveRequest::AsyncApplyFilters::Cancel(nsresult reason)
627
0
{
628
0
  LOG(("AsyncApplyFilters::Cancel %p", this));
629
0
630
0
  MOZ_ASSERT(mProcessingThread && mProcessingThread->IsOnCurrentThread());
631
0
632
0
  // This will be called only from inside the request, so don't call
633
0
  // its's callback.  Dropping the members means we simply break the cycle.
634
0
  mFiltersCopy.Clear();
635
0
  mProxyInfo = nullptr;
636
0
  mRequest = nullptr;
637
0
638
0
  return NS_OK;
639
0
}
640
641
// Bug 1366133: make GetPACURI off-main-thread since it may hang on Windows platform
642
class AsyncGetPACURIRequest final : public nsIRunnable
643
{
644
public:
645
    NS_DECL_THREADSAFE_ISUPPORTS
646
647
    using CallbackFunc = nsresult(nsProtocolProxyService::*)(bool, bool, nsresult, const nsACString&);
648
649
    AsyncGetPACURIRequest(nsProtocolProxyService* aService,
650
                          CallbackFunc aCallback,
651
                          nsISystemProxySettings* aSystemProxySettings,
652
                          bool aMainThreadOnly,
653
                          bool aForceReload,
654
                          bool aResetPACThread)
655
        : mIsMainThreadOnly(aMainThreadOnly)
656
        , mService(aService)
657
        , mServiceHolder(do_QueryObject(aService))
658
        , mCallback(aCallback)
659
        , mSystemProxySettings(aSystemProxySettings)
660
        , mForceReload(aForceReload)
661
        , mResetPACThread(aResetPACThread)
662
0
    {
663
0
        MOZ_ASSERT(NS_IsMainThread());
664
0
        Unused << mIsMainThreadOnly;
665
0
    }
666
667
    NS_IMETHOD Run() override
668
0
    {
669
0
        MOZ_ASSERT(NS_IsMainThread() == mIsMainThreadOnly);
670
0
671
0
        nsCString pacUri;
672
0
        nsresult rv = mSystemProxySettings->GetPACURI(pacUri);
673
0
674
0
        nsCOMPtr<nsIRunnable> event =
675
0
            NewNonOwningCancelableRunnableMethod<bool,
676
0
                                                 bool,
677
0
                                                 nsresult,
678
0
                                                 nsCString>("AsyncGetPACURIRequestCallback",
679
0
                                                             mService,
680
0
                                                             mCallback,
681
0
                                                             mForceReload,
682
0
                                                             mResetPACThread,
683
0
                                                             rv,
684
0
                                                             pacUri);
685
0
686
0
        return NS_DispatchToMainThread(event);
687
0
    }
688
689
private:
690
    ~AsyncGetPACURIRequest()
691
0
    {
692
0
        NS_ReleaseOnMainThreadSystemGroup(
693
0
          "AsyncGetPACURIRequest::mServiceHolder", mServiceHolder.forget());
694
0
    }
695
696
    bool mIsMainThreadOnly;
697
698
    nsProtocolProxyService* mService; // ref-count is hold by mServiceHolder
699
    nsCOMPtr<nsIProtocolProxyService2> mServiceHolder;
700
    CallbackFunc mCallback;
701
    nsCOMPtr<nsISystemProxySettings> mSystemProxySettings;
702
703
    bool mForceReload;
704
    bool mResetPACThread;
705
};
706
707
NS_IMPL_ISUPPORTS(AsyncGetPACURIRequest, nsIRunnable)
708
709
//----------------------------------------------------------------------------
710
711
//
712
// apply mask to address (zeros out excluded bits).
713
//
714
// NOTE: we do the byte swapping here to minimize overall swapping.
715
//
716
static void
717
proxy_MaskIPv6Addr(PRIPv6Addr &addr, uint16_t mask_len)
718
0
{
719
0
    if (mask_len == 128)
720
0
        return;
721
0
722
0
    if (mask_len > 96) {
723
0
        addr.pr_s6_addr32[3] = PR_htonl(
724
0
                PR_ntohl(addr.pr_s6_addr32[3]) & (~0L << (128 - mask_len)));
725
0
    }
726
0
    else if (mask_len > 64) {
727
0
        addr.pr_s6_addr32[3] = 0;
728
0
        addr.pr_s6_addr32[2] = PR_htonl(
729
0
                PR_ntohl(addr.pr_s6_addr32[2]) & (~0L << (96 - mask_len)));
730
0
    }
731
0
    else if (mask_len > 32) {
732
0
        addr.pr_s6_addr32[3] = 0;
733
0
        addr.pr_s6_addr32[2] = 0;
734
0
        addr.pr_s6_addr32[1] = PR_htonl(
735
0
                PR_ntohl(addr.pr_s6_addr32[1]) & (~0L << (64 - mask_len)));
736
0
    }
737
0
    else {
738
0
        addr.pr_s6_addr32[3] = 0;
739
0
        addr.pr_s6_addr32[2] = 0;
740
0
        addr.pr_s6_addr32[1] = 0;
741
0
        addr.pr_s6_addr32[0] = PR_htonl(
742
0
                PR_ntohl(addr.pr_s6_addr32[0]) & (~0L << (32 - mask_len)));
743
0
    }
744
0
}
745
746
static void
747
proxy_GetStringPref(nsIPrefBranch *aPrefBranch,
748
                    const char    *aPref,
749
                    nsCString     &aResult)
750
0
{
751
0
    nsAutoCString temp;
752
0
    nsresult rv = aPrefBranch->GetCharPref(aPref, temp);
753
0
    if (NS_FAILED(rv))
754
0
        aResult.Truncate();
755
0
    else {
756
0
        aResult.Assign(temp);
757
0
        // all of our string prefs are hostnames, so we should remove any
758
0
        // whitespace characters that the user might have unknowingly entered.
759
0
        aResult.StripWhitespace();
760
0
    }
761
0
}
762
763
static void
764
proxy_GetIntPref(nsIPrefBranch *aPrefBranch,
765
                 const char    *aPref,
766
                 int32_t       &aResult)
767
0
{
768
0
    int32_t temp;
769
0
    nsresult rv = aPrefBranch->GetIntPref(aPref, &temp);
770
0
    if (NS_FAILED(rv))
771
0
        aResult = -1;
772
0
    else
773
0
        aResult = temp;
774
0
}
775
776
static void
777
proxy_GetBoolPref(nsIPrefBranch *aPrefBranch,
778
                 const char    *aPref,
779
                 bool          &aResult)
780
0
{
781
0
    bool temp;
782
0
    nsresult rv = aPrefBranch->GetBoolPref(aPref, &temp);
783
0
    if (NS_FAILED(rv))
784
0
        aResult = false;
785
0
    else
786
0
        aResult = temp;
787
0
}
788
789
//----------------------------------------------------------------------------
790
791
static const int32_t PROXYCONFIG_DIRECT4X = 3;
792
static const int32_t PROXYCONFIG_COUNT = 6;
793
794
NS_IMPL_ADDREF(nsProtocolProxyService)
795
NS_IMPL_RELEASE(nsProtocolProxyService)
796
NS_IMPL_CLASSINFO(nsProtocolProxyService, nullptr, nsIClassInfo::SINGLETON,
797
                  NS_PROTOCOLPROXYSERVICE_CID)
798
799
// NS_IMPL_QUERY_INTERFACE_CI with the nsProtocolProxyService QI change
800
0
NS_INTERFACE_MAP_BEGIN(nsProtocolProxyService)
801
0
NS_INTERFACE_MAP_ENTRY(nsIProtocolProxyService)
802
0
NS_INTERFACE_MAP_ENTRY(nsIProtocolProxyService2)
803
0
NS_INTERFACE_MAP_ENTRY(nsIObserver)
804
0
NS_INTERFACE_MAP_ENTRY_CONCRETE(nsProtocolProxyService)
805
0
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIProtocolProxyService)
806
0
NS_IMPL_QUERY_CLASSINFO(nsProtocolProxyService)
807
0
NS_INTERFACE_MAP_END
808
809
NS_IMPL_CI_INTERFACE_GETTER(nsProtocolProxyService,
810
                            nsIProtocolProxyService,
811
                            nsIProtocolProxyService2)
812
813
nsProtocolProxyService::nsProtocolProxyService()
814
    : mFilterLocalHosts(false)
815
    , mProxyConfig(PROXYCONFIG_DIRECT)
816
    , mHTTPProxyPort(-1)
817
    , mFTPProxyPort(-1)
818
    , mHTTPSProxyPort(-1)
819
    , mSOCKSProxyPort(-1)
820
    , mSOCKSProxyVersion(4)
821
    , mSOCKSProxyRemoteDNS(false)
822
    , mProxyOverTLS(true)
823
    , mWPADOverDHCPEnabled(false)
824
    , mPACMan(nullptr)
825
    , mSessionStart(PR_Now())
826
    , mFailedProxyTimeout(30 * 60) // 30 minute default
827
    , mIsShutdown(false)
828
0
{
829
0
}
830
831
nsProtocolProxyService::~nsProtocolProxyService()
832
0
{
833
0
    // These should have been cleaned up in our Observe method.
834
0
    NS_ASSERTION(mHostFiltersArray.Length() == 0 && mFilters.Length() == 0 &&
835
0
                 mPACMan == nullptr, "what happened to xpcom-shutdown?");
836
0
}
837
838
// nsProtocolProxyService methods
839
nsresult
840
nsProtocolProxyService::Init()
841
0
{
842
0
    mProxySettingTarget = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
843
0
844
0
    // failure to access prefs is non-fatal
845
0
    nsCOMPtr<nsIPrefBranch> prefBranch =
846
0
            do_GetService(NS_PREFSERVICE_CONTRACTID);
847
0
    if (prefBranch) {
848
0
        // monitor proxy prefs
849
0
        prefBranch->AddObserver(PROXY_PREF_BRANCH, this, false);
850
0
851
0
        // read all prefs
852
0
        PrefsChanged(prefBranch, nullptr);
853
0
    }
854
0
855
0
    nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
856
0
    if (obs) {
857
0
        // register for shutdown notification so we can clean ourselves up
858
0
        // properly.
859
0
        obs->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
860
0
        obs->AddObserver(this, NS_NETWORK_LINK_TOPIC, false);
861
0
    }
862
0
863
0
    return NS_OK;
864
0
}
865
866
// ReloadNetworkPAC() checks if there's a non-networked PAC in use then avoids
867
// to call ReloadPAC()
868
nsresult
869
nsProtocolProxyService::ReloadNetworkPAC()
870
0
{
871
0
    nsCOMPtr<nsIPrefBranch> prefs =
872
0
        do_GetService(NS_PREFSERVICE_CONTRACTID);
873
0
    if (!prefs) {
874
0
        return NS_OK;
875
0
    }
876
0
877
0
    int32_t type;
878
0
    nsresult rv = prefs->GetIntPref(PROXY_PREF("type"), &type);
879
0
    if (NS_FAILED(rv)) {
880
0
        return NS_OK;
881
0
    }
882
0
883
0
    if (type == PROXYCONFIG_PAC) {
884
0
        nsAutoCString pacSpec;
885
0
        prefs->GetCharPref(PROXY_PREF("autoconfig_url"), pacSpec);
886
0
        if (!pacSpec.IsEmpty()) {
887
0
            nsCOMPtr<nsIURI> pacURI;
888
0
            rv = NS_NewURI(getter_AddRefs(pacURI), pacSpec);
889
0
            if(!NS_SUCCEEDED(rv)) {
890
0
                return rv;
891
0
            }
892
0
893
0
            nsProtocolInfo pac;
894
0
            rv = GetProtocolInfo(pacURI, &pac);
895
0
            if(!NS_SUCCEEDED(rv)) {
896
0
                return rv;
897
0
            }
898
0
899
0
            if (!pac.scheme.EqualsLiteral("file") &&
900
0
                !pac.scheme.EqualsLiteral("data")) {
901
0
                LOG((": received network changed event, reload PAC"));
902
0
                ReloadPAC();
903
0
            }
904
0
        }
905
0
    } else if ((type == PROXYCONFIG_WPAD) || (type == PROXYCONFIG_SYSTEM)) {
906
0
        ReloadPAC();
907
0
    }
908
0
909
0
    return NS_OK;
910
0
}
911
912
nsresult
913
nsProtocolProxyService::AsyncConfigureFromPAC(bool aForceReload,
914
                                              bool aResetPACThread)
915
0
{
916
0
    MOZ_ASSERT(NS_IsMainThread());
917
0
918
0
    bool mainThreadOnly;
919
0
    nsresult rv = mSystemProxySettings->GetMainThreadOnly(&mainThreadOnly);
920
0
    if (NS_WARN_IF(NS_FAILED(rv))) {
921
0
        return rv;
922
0
    }
923
0
924
0
    nsCOMPtr<nsIRunnable> req =
925
0
        new AsyncGetPACURIRequest(this,
926
0
                                  &nsProtocolProxyService::OnAsyncGetPACURI,
927
0
                                  mSystemProxySettings,
928
0
                                  mainThreadOnly,
929
0
                                  aForceReload,
930
0
                                  aResetPACThread);
931
0
932
0
    if (mainThreadOnly) {
933
0
        return req->Run();
934
0
    }
935
0
936
0
    if (NS_WARN_IF(!mProxySettingTarget)) {
937
0
        return NS_ERROR_NOT_INITIALIZED;
938
0
    }
939
0
    return mProxySettingTarget->Dispatch(req, nsIEventTarget::DISPATCH_NORMAL);
940
0
}
941
942
nsresult
943
nsProtocolProxyService::OnAsyncGetPACURI(bool aForceReload,
944
                                         bool aResetPACThread,
945
                                         nsresult aResult,
946
                                         const nsACString& aUri)
947
0
{
948
0
    MOZ_ASSERT(NS_IsMainThread());
949
0
950
0
    if (aResetPACThread) {
951
0
        ResetPACThread();
952
0
    }
953
0
954
0
    if (NS_SUCCEEDED(aResult) && !aUri.IsEmpty()) {
955
0
        ConfigureFromPAC(PromiseFlatCString(aUri), aForceReload);
956
0
    }
957
0
958
0
    return NS_OK;
959
0
}
960
961
NS_IMETHODIMP
962
nsProtocolProxyService::Observe(nsISupports     *aSubject,
963
                                const char      *aTopic,
964
                                const char16_t *aData)
965
0
{
966
0
    if (strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0) {
967
0
        mIsShutdown = true;
968
0
        // cleanup
969
0
        mHostFiltersArray.Clear();
970
0
        mFilters.Clear();
971
0
972
0
        if (mPACMan) {
973
0
            mPACMan->Shutdown();
974
0
            mPACMan = nullptr;
975
0
        }
976
0
977
0
        if (mProxySettingTarget) {
978
0
            mProxySettingTarget = nullptr;
979
0
        }
980
0
981
0
        nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
982
0
        if (obs) {
983
0
            obs->RemoveObserver(this, NS_NETWORK_LINK_TOPIC);
984
0
            obs->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
985
0
        }
986
0
987
0
    } else if (strcmp(aTopic, NS_NETWORK_LINK_TOPIC) == 0) {
988
0
        nsCString converted = NS_ConvertUTF16toUTF8(aData);
989
0
        const char *state = converted.get();
990
0
        if (!strcmp(state, NS_NETWORK_LINK_DATA_CHANGED)) {
991
0
            ReloadNetworkPAC();
992
0
        }
993
0
    }
994
0
    else {
995
0
        NS_ASSERTION(strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID) == 0,
996
0
                     "what is this random observer event?");
997
0
        nsCOMPtr<nsIPrefBranch> prefs = do_QueryInterface(aSubject);
998
0
        if (prefs)
999
0
            PrefsChanged(prefs, NS_LossyConvertUTF16toASCII(aData).get());
1000
0
    }
1001
0
    return NS_OK;
1002
0
}
1003
1004
void
1005
nsProtocolProxyService::PrefsChanged(nsIPrefBranch *prefBranch,
1006
                                     const char    *pref)
1007
0
{
1008
0
    nsresult rv = NS_OK;
1009
0
    bool reloadPAC = false;
1010
0
    nsAutoCString tempString;
1011
0
1012
0
    if (!pref || !strcmp(pref, PROXY_PREF("type"))) {
1013
0
        int32_t type = -1;
1014
0
        rv = prefBranch->GetIntPref(PROXY_PREF("type"), &type);
1015
0
        if (NS_SUCCEEDED(rv)) {
1016
0
            // bug 115720 - for ns4.x backwards compatibility
1017
0
            if (type == PROXYCONFIG_DIRECT4X) {
1018
0
                type = PROXYCONFIG_DIRECT;
1019
0
                // Reset the type so that the dialog looks correct, and we
1020
0
                // don't have to handle this case everywhere else
1021
0
                // I'm paranoid about a loop of some sort - only do this
1022
0
                // if we're enumerating all prefs, and ignore any error
1023
0
                if (!pref)
1024
0
                    prefBranch->SetIntPref(PROXY_PREF("type"), type);
1025
0
            } else if (type >= PROXYCONFIG_COUNT) {
1026
0
                LOG(("unknown proxy type: %" PRId32 "; assuming direct\n", type));
1027
0
                type = PROXYCONFIG_DIRECT;
1028
0
            }
1029
0
            mProxyConfig = type;
1030
0
            reloadPAC = true;
1031
0
        }
1032
0
1033
0
        if (mProxyConfig == PROXYCONFIG_SYSTEM) {
1034
0
            mSystemProxySettings = do_GetService(NS_SYSTEMPROXYSETTINGS_CONTRACTID);
1035
0
            if (!mSystemProxySettings)
1036
0
                mProxyConfig = PROXYCONFIG_DIRECT;
1037
0
            ResetPACThread();
1038
0
        } else {
1039
0
            if (mSystemProxySettings) {
1040
0
                mSystemProxySettings = nullptr;
1041
0
                ResetPACThread();
1042
0
            }
1043
0
        }
1044
0
    }
1045
0
1046
0
    if (!pref || !strcmp(pref, PROXY_PREF("http")))
1047
0
        proxy_GetStringPref(prefBranch, PROXY_PREF("http"), mHTTPProxyHost);
1048
0
1049
0
    if (!pref || !strcmp(pref, PROXY_PREF("http_port")))
1050
0
        proxy_GetIntPref(prefBranch, PROXY_PREF("http_port"), mHTTPProxyPort);
1051
0
1052
0
    if (!pref || !strcmp(pref, PROXY_PREF("ssl")))
1053
0
        proxy_GetStringPref(prefBranch, PROXY_PREF("ssl"), mHTTPSProxyHost);
1054
0
1055
0
    if (!pref || !strcmp(pref, PROXY_PREF("ssl_port")))
1056
0
        proxy_GetIntPref(prefBranch, PROXY_PREF("ssl_port"), mHTTPSProxyPort);
1057
0
1058
0
    if (!pref || !strcmp(pref, PROXY_PREF("ftp")))
1059
0
        proxy_GetStringPref(prefBranch, PROXY_PREF("ftp"), mFTPProxyHost);
1060
0
1061
0
    if (!pref || !strcmp(pref, PROXY_PREF("ftp_port")))
1062
0
        proxy_GetIntPref(prefBranch, PROXY_PREF("ftp_port"), mFTPProxyPort);
1063
0
1064
0
    if (!pref || !strcmp(pref, PROXY_PREF("socks")))
1065
0
        proxy_GetStringPref(prefBranch, PROXY_PREF("socks"), mSOCKSProxyTarget);
1066
0
1067
0
    if (!pref || !strcmp(pref, PROXY_PREF("socks_port")))
1068
0
        proxy_GetIntPref(prefBranch, PROXY_PREF("socks_port"), mSOCKSProxyPort);
1069
0
1070
0
    if (!pref || !strcmp(pref, PROXY_PREF("socks_version"))) {
1071
0
        int32_t version;
1072
0
        proxy_GetIntPref(prefBranch, PROXY_PREF("socks_version"), version);
1073
0
        // make sure this preference value remains sane
1074
0
        if (version == 5)
1075
0
            mSOCKSProxyVersion = 5;
1076
0
        else
1077
0
            mSOCKSProxyVersion = 4;
1078
0
    }
1079
0
1080
0
    if (!pref || !strcmp(pref, PROXY_PREF("socks_remote_dns")))
1081
0
        proxy_GetBoolPref(prefBranch, PROXY_PREF("socks_remote_dns"),
1082
0
                          mSOCKSProxyRemoteDNS);
1083
0
1084
0
    if (!pref || !strcmp(pref, PROXY_PREF("proxy_over_tls"))) {
1085
0
        proxy_GetBoolPref(prefBranch, PROXY_PREF("proxy_over_tls"),
1086
0
                          mProxyOverTLS);
1087
0
    }
1088
0
1089
0
    if (!pref || !strcmp(pref, PROXY_PREF("enable_wpad_over_dhcp"))) {
1090
0
        proxy_GetBoolPref(prefBranch, PROXY_PREF("enable_wpad_over_dhcp"),
1091
0
                          mWPADOverDHCPEnabled);
1092
0
        reloadPAC = reloadPAC || mProxyConfig == PROXYCONFIG_WPAD;
1093
0
    }
1094
0
1095
0
    if (!pref || !strcmp(pref, PROXY_PREF("failover_timeout")))
1096
0
        proxy_GetIntPref(prefBranch, PROXY_PREF("failover_timeout"),
1097
0
                         mFailedProxyTimeout);
1098
0
1099
0
    if (!pref || !strcmp(pref, PROXY_PREF("no_proxies_on"))) {
1100
0
        rv = prefBranch->GetCharPref(PROXY_PREF("no_proxies_on"), tempString);
1101
0
        if (NS_SUCCEEDED(rv))
1102
0
            LoadHostFilters(tempString);
1103
0
    }
1104
0
1105
0
    // We're done if not using something that could give us a PAC URL
1106
0
    // (PAC, WPAD or System)
1107
0
    if (mProxyConfig != PROXYCONFIG_PAC && mProxyConfig != PROXYCONFIG_WPAD &&
1108
0
        mProxyConfig != PROXYCONFIG_SYSTEM)
1109
0
        return;
1110
0
1111
0
    // OK, we need to reload the PAC file if:
1112
0
    //  1) network.proxy.type changed, or
1113
0
    //  2) network.proxy.autoconfig_url changed and PAC is configured
1114
0
1115
0
    if (!pref || !strcmp(pref, PROXY_PREF("autoconfig_url")))
1116
0
        reloadPAC = true;
1117
0
1118
0
    if (reloadPAC) {
1119
0
        tempString.Truncate();
1120
0
        if (mProxyConfig == PROXYCONFIG_PAC) {
1121
0
            prefBranch->GetCharPref(PROXY_PREF("autoconfig_url"), tempString);
1122
0
            if (mPACMan && !mPACMan->IsPACURI(tempString)) {
1123
0
                LOG(("PAC Thread URI Changed - Reset Pac Thread"));
1124
0
                ResetPACThread();
1125
0
            }
1126
0
        } else if (mProxyConfig == PROXYCONFIG_WPAD) {
1127
0
            LOG(("Auto-detecting proxy - Reset Pac Thread"));
1128
0
            ResetPACThread();
1129
0
        } else if (mSystemProxySettings) {
1130
0
            // Get System Proxy settings if available
1131
0
            AsyncConfigureFromPAC(false, false);
1132
0
        }
1133
0
        if (!tempString.IsEmpty() || mProxyConfig == PROXYCONFIG_WPAD) {
1134
0
            ConfigureFromPAC(tempString, false);
1135
0
        }
1136
0
    }
1137
0
}
1138
1139
bool
1140
nsProtocolProxyService::CanUseProxy(nsIURI *aURI, int32_t defaultPort)
1141
0
{
1142
0
    if (mHostFiltersArray.Length() == 0 && !mFilterLocalHosts)
1143
0
        return true;
1144
0
1145
0
    int32_t port;
1146
0
    nsAutoCString host;
1147
0
1148
0
    nsresult rv = aURI->GetAsciiHost(host);
1149
0
    if (NS_FAILED(rv) || host.IsEmpty())
1150
0
        return false;
1151
0
1152
0
    rv = aURI->GetPort(&port);
1153
0
    if (NS_FAILED(rv))
1154
0
        return false;
1155
0
    if (port == -1)
1156
0
        port = defaultPort;
1157
0
1158
0
    PRNetAddr addr;
1159
0
    bool is_ipaddr = (PR_StringToNetAddr(host.get(), &addr) == PR_SUCCESS);
1160
0
1161
0
    PRIPv6Addr ipv6;
1162
0
    if (is_ipaddr) {
1163
0
        // convert parsed address to IPv6
1164
0
        if (addr.raw.family == PR_AF_INET) {
1165
0
            // convert to IPv4-mapped address
1166
0
            PR_ConvertIPv4AddrToIPv6(addr.inet.ip, &ipv6);
1167
0
        }
1168
0
        else if (addr.raw.family == PR_AF_INET6) {
1169
0
            // copy the address
1170
0
            memcpy(&ipv6, &addr.ipv6.ip, sizeof(PRIPv6Addr));
1171
0
        }
1172
0
        else {
1173
0
            NS_WARNING("unknown address family");
1174
0
            return true; // allow proxying
1175
0
        }
1176
0
    }
1177
0
1178
0
    // Don't use proxy for local hosts (plain hostname, no dots)
1179
0
    if ((!is_ipaddr && mFilterLocalHosts && !host.Contains('.')) ||
1180
0
        host.EqualsLiteral("127.0.0.1") ||
1181
0
        host.EqualsLiteral("::1")) {
1182
0
        LOG(("Not using proxy for this local host [%s]!\n", host.get()));
1183
0
        return false; // don't allow proxying
1184
0
    }
1185
0
1186
0
    int32_t index = -1;
1187
0
    while (++index < int32_t(mHostFiltersArray.Length())) {
1188
0
        HostInfo *hinfo = mHostFiltersArray[index];
1189
0
1190
0
        if (is_ipaddr != hinfo->is_ipaddr)
1191
0
            continue;
1192
0
        if (hinfo->port && hinfo->port != port)
1193
0
            continue;
1194
0
1195
0
        if (is_ipaddr) {
1196
0
            // generate masked version of target IPv6 address
1197
0
            PRIPv6Addr masked;
1198
0
            memcpy(&masked, &ipv6, sizeof(PRIPv6Addr));
1199
0
            proxy_MaskIPv6Addr(masked, hinfo->ip.mask_len);
1200
0
1201
0
            // check for a match
1202
0
            if (memcmp(&masked, &hinfo->ip.addr, sizeof(PRIPv6Addr)) == 0)
1203
0
                return false; // proxy disallowed
1204
0
        }
1205
0
        else {
1206
0
            uint32_t host_len = host.Length();
1207
0
            uint32_t filter_host_len = hinfo->name.host_len;
1208
0
1209
0
            if (host_len >= filter_host_len) {
1210
0
                //
1211
0
                // compare last |filter_host_len| bytes of target hostname.
1212
0
                //
1213
0
                const char *host_tail = host.get() + host_len - filter_host_len;
1214
0
                if (!PL_strncasecmp(host_tail, hinfo->name.host, filter_host_len)) {
1215
0
                    // If the tail of the host string matches the filter
1216
0
1217
0
                    if (filter_host_len > 0 && hinfo->name.host[0] == '.') {
1218
0
                        // If the filter was of the form .foo.bar.tld, all such
1219
0
                        // matches are correct
1220
0
                        return false; // proxy disallowed
1221
0
                    }
1222
0
1223
0
                    // abc-def.example.org should not match def.example.org
1224
0
                    // however, *.def.example.org should match .def.example.org
1225
0
                    // We check that the filter doesn't start with a `.`. If it does,
1226
0
                    // then the strncasecmp above should suffice. If it doesn't,
1227
0
                    // then we should only consider it a match if the strncasecmp happened
1228
0
                    // at a subdomain boundary
1229
0
                    if (host_len > filter_host_len && *(host_tail - 1) == '.') {
1230
0
                            // If the host was something.foo.bar.tld and the filter
1231
0
                            // was foo.bar.tld, it's still a match.
1232
0
                            // the character right before the tail must be a
1233
0
                            // `.` for this to work
1234
0
                            return false; // proxy disallowed
1235
0
                    }
1236
0
1237
0
                    if (host_len == filter_host_len) {
1238
0
                        // If the host and filter are of the same length,
1239
0
                        // they should match
1240
0
                        return false; // proxy disallowed
1241
0
                    }
1242
0
                }
1243
0
1244
0
            }
1245
0
        }
1246
0
    }
1247
0
    return true;
1248
0
}
1249
1250
// kProxyType\* may be referred to externally in
1251
// nsProxyInfo in order to compare by string pointer
1252
const char kProxyType_HTTP[]    = "http";
1253
const char kProxyType_HTTPS[]   = "https";
1254
const char kProxyType_PROXY[]   = "proxy";
1255
const char kProxyType_SOCKS[]   = "socks";
1256
const char kProxyType_SOCKS4[]  = "socks4";
1257
const char kProxyType_SOCKS5[]  = "socks5";
1258
const char kProxyType_DIRECT[]  = "direct";
1259
1260
const char *
1261
nsProtocolProxyService::ExtractProxyInfo(const char *start,
1262
                                         uint32_t aResolveFlags,
1263
                                         nsProxyInfo **result)
1264
0
{
1265
0
    *result = nullptr;
1266
0
    uint32_t flags = 0;
1267
0
1268
0
    // see BNF in ProxyAutoConfig.h and notes in nsISystemProxySettings.idl
1269
0
1270
0
    // find end of proxy info delimiter
1271
0
    const char *end = start;
1272
0
    while (*end && *end != ';') ++end;
1273
0
1274
0
    // find end of proxy type delimiter
1275
0
    const char *sp = start;
1276
0
    while (sp < end && *sp != ' ' && *sp != '\t') ++sp;
1277
0
1278
0
    uint32_t len = sp - start;
1279
0
    const char *type = nullptr;
1280
0
    switch (len) {
1281
0
    case 4:
1282
0
        if (PL_strncasecmp(start, kProxyType_HTTP, 5) == 0) {
1283
0
            type = kProxyType_HTTP;
1284
0
        }
1285
0
        break;
1286
0
    case 5:
1287
0
        if (PL_strncasecmp(start, kProxyType_PROXY, 5) == 0) {
1288
0
            type = kProxyType_HTTP;
1289
0
        } else if (PL_strncasecmp(start, kProxyType_SOCKS, 5) == 0) {
1290
0
            type = kProxyType_SOCKS4; // assume v4 for 4x compat
1291
0
        } else if (PL_strncasecmp(start, kProxyType_HTTPS, 5) == 0) {
1292
0
            type = kProxyType_HTTPS;
1293
0
        }
1294
0
        break;
1295
0
    case 6:
1296
0
        if (PL_strncasecmp(start, kProxyType_DIRECT, 6) == 0)
1297
0
            type = kProxyType_DIRECT;
1298
0
        else if (PL_strncasecmp(start, kProxyType_SOCKS4, 6) == 0)
1299
0
            type = kProxyType_SOCKS4;
1300
0
        else if (PL_strncasecmp(start, kProxyType_SOCKS5, 6) == 0)
1301
0
            // map "SOCKS5" to "socks" to match contract-id of registered
1302
0
            // SOCKS-v5 socket provider.
1303
0
            type = kProxyType_SOCKS;
1304
0
        break;
1305
0
    }
1306
0
    if (type) {
1307
0
        const char *host = nullptr, *hostEnd = nullptr;
1308
0
        int32_t port = -1;
1309
0
1310
0
        // If it's a SOCKS5 proxy, do name resolution on the server side.
1311
0
        // We could use this with SOCKS4a servers too, but they might not
1312
0
        // support it.
1313
0
        if (type == kProxyType_SOCKS || mSOCKSProxyRemoteDNS)
1314
0
            flags |= nsIProxyInfo::TRANSPARENT_PROXY_RESOLVES_HOST;
1315
0
1316
0
        // extract host:port
1317
0
        start = sp;
1318
0
        while ((*start == ' ' || *start == '\t') && start < end)
1319
0
            start++;
1320
0
1321
0
        // port defaults
1322
0
        if (type == kProxyType_HTTP) {
1323
0
            port = 80;
1324
0
        } else if (type == kProxyType_HTTPS) {
1325
0
            port = 443;
1326
0
        } else {
1327
0
            port = 1080;
1328
0
        }
1329
0
1330
0
        nsProxyInfo *pi = new nsProxyInfo();
1331
0
        pi->mType = type;
1332
0
        pi->mFlags = flags;
1333
0
        pi->mResolveFlags = aResolveFlags;
1334
0
        pi->mTimeout = mFailedProxyTimeout;
1335
0
1336
0
        // www.foo.com:8080 and http://www.foo.com:8080
1337
0
        nsDependentCSubstring maybeURL(start, end - start);
1338
0
        nsCOMPtr<nsIURI> pacURI;
1339
0
1340
0
        nsAutoCString urlHost;
1341
0
        if (NS_SUCCEEDED(NS_NewURI(getter_AddRefs(pacURI), maybeURL)) &&
1342
0
            NS_SUCCEEDED(pacURI->GetAsciiHost(urlHost)) &&
1343
0
            !urlHost.IsEmpty()) {
1344
0
            // http://www.example.com:8080
1345
0
1346
0
            pi->mHost = urlHost;
1347
0
1348
0
            int32_t tPort;
1349
0
            if (NS_SUCCEEDED(pacURI->GetPort(&tPort)) && tPort != -1) {
1350
0
                port = tPort;
1351
0
            }
1352
0
            pi->mPort = port;
1353
0
        }
1354
0
        else {
1355
0
            // www.example.com:8080
1356
0
            if (start < end) {
1357
0
                host = start;
1358
0
                hostEnd = strchr(host, ':');
1359
0
                if (!hostEnd || hostEnd > end) {
1360
0
                    hostEnd = end;
1361
0
                    // no port, so assume default
1362
0
                }
1363
0
                else {
1364
0
                    port = atoi(hostEnd + 1);
1365
0
                }
1366
0
            }
1367
0
            // YES, it is ok to specify a null proxy host.
1368
0
            if (host) {
1369
0
                pi->mHost.Assign(host, hostEnd - host);
1370
0
                pi->mPort = port;
1371
0
            }
1372
0
        }
1373
0
        NS_ADDREF(*result = pi);
1374
0
    }
1375
0
1376
0
    while (*end == ';' || *end == ' ' || *end == '\t')
1377
0
        ++end;
1378
0
    return end;
1379
0
}
1380
1381
void
1382
nsProtocolProxyService::GetProxyKey(nsProxyInfo *pi, nsCString &key)
1383
0
{
1384
0
    key.AssignASCII(pi->mType);
1385
0
    if (!pi->mHost.IsEmpty()) {
1386
0
        key.Append(' ');
1387
0
        key.Append(pi->mHost);
1388
0
        key.Append(':');
1389
0
        key.AppendInt(pi->mPort);
1390
0
    }
1391
0
}
1392
1393
uint32_t
1394
nsProtocolProxyService::SecondsSinceSessionStart()
1395
0
{
1396
0
    PRTime now = PR_Now();
1397
0
1398
0
    // get time elapsed since session start
1399
0
    int64_t diff = now - mSessionStart;
1400
0
1401
0
    // convert microseconds to seconds
1402
0
    diff /= PR_USEC_PER_SEC;
1403
0
1404
0
    // return converted 32 bit value
1405
0
    return uint32_t(diff);
1406
0
}
1407
1408
void
1409
nsProtocolProxyService::EnableProxy(nsProxyInfo *pi)
1410
0
{
1411
0
    nsAutoCString key;
1412
0
    GetProxyKey(pi, key);
1413
0
    mFailedProxies.Remove(key);
1414
0
}
1415
1416
void
1417
nsProtocolProxyService::DisableProxy(nsProxyInfo *pi)
1418
0
{
1419
0
    nsAutoCString key;
1420
0
    GetProxyKey(pi, key);
1421
0
1422
0
    uint32_t dsec = SecondsSinceSessionStart();
1423
0
1424
0
    // Add timeout to interval (this is the time when the proxy can
1425
0
    // be tried again).
1426
0
    dsec += pi->mTimeout;
1427
0
1428
0
    // NOTE: The classic codebase would increase the timeout value
1429
0
    //       incrementally each time a subsequent failure occurred.
1430
0
    //       We could do the same, but it would require that we not
1431
0
    //       remove proxy entries in IsProxyDisabled or otherwise
1432
0
    //       change the way we are recording disabled proxies.
1433
0
    //       Simpler is probably better for now, and at least the
1434
0
    //       user can tune the timeout setting via preferences.
1435
0
1436
0
    LOG(("DisableProxy %s %d\n", key.get(), dsec));
1437
0
1438
0
    // If this fails, oh well... means we don't have enough memory
1439
0
    // to remember the failed proxy.
1440
0
    mFailedProxies.Put(key, dsec);
1441
0
}
1442
1443
bool
1444
nsProtocolProxyService::IsProxyDisabled(nsProxyInfo *pi)
1445
0
{
1446
0
    nsAutoCString key;
1447
0
    GetProxyKey(pi, key);
1448
0
1449
0
    uint32_t val;
1450
0
    if (!mFailedProxies.Get(key, &val))
1451
0
        return false;
1452
0
1453
0
    uint32_t dsec = SecondsSinceSessionStart();
1454
0
1455
0
    // if time passed has exceeded interval, then try proxy again.
1456
0
    if (dsec > val) {
1457
0
        mFailedProxies.Remove(key);
1458
0
        return false;
1459
0
    }
1460
0
1461
0
    return true;
1462
0
}
1463
1464
nsresult
1465
nsProtocolProxyService::SetupPACThread(nsIEventTarget *mainThreadEventTarget)
1466
0
{
1467
0
    if (mIsShutdown) {
1468
0
        return NS_ERROR_FAILURE;
1469
0
    }
1470
0
1471
0
    if (mPACMan)
1472
0
        return NS_OK;
1473
0
1474
0
    mPACMan = new nsPACMan(mainThreadEventTarget);
1475
0
1476
0
    bool mainThreadOnly;
1477
0
    nsresult rv;
1478
0
    if (mSystemProxySettings &&
1479
0
        NS_SUCCEEDED(mSystemProxySettings->GetMainThreadOnly(&mainThreadOnly)) &&
1480
0
        !mainThreadOnly) {
1481
0
        rv = mPACMan->Init(mSystemProxySettings);
1482
0
    }
1483
0
    else {
1484
0
        rv = mPACMan->Init(nullptr);
1485
0
    }
1486
0
    if (NS_FAILED(rv)) {
1487
0
        mPACMan->Shutdown();
1488
0
        mPACMan = nullptr;
1489
0
    }
1490
0
    return rv;
1491
0
}
1492
1493
nsresult
1494
nsProtocolProxyService::ResetPACThread()
1495
0
{
1496
0
    if (!mPACMan)
1497
0
        return NS_OK;
1498
0
1499
0
    mPACMan->Shutdown();
1500
0
    mPACMan = nullptr;
1501
0
    return SetupPACThread();
1502
0
}
1503
1504
nsresult
1505
nsProtocolProxyService::ConfigureFromPAC(const nsCString &spec,
1506
                                         bool forceReload)
1507
0
{
1508
0
    nsresult rv = SetupPACThread();
1509
0
    NS_ENSURE_SUCCESS(rv, rv);
1510
0
1511
0
    bool autodetect = spec.IsEmpty();
1512
0
    if (!forceReload && ((!autodetect && mPACMan->IsPACURI(spec)) ||
1513
0
                         (autodetect && mPACMan->IsUsingWPAD()))) {
1514
0
        return NS_OK;
1515
0
    }
1516
0
1517
0
    mFailedProxies.Clear();
1518
0
1519
0
    mPACMan->SetWPADOverDHCPEnabled(mWPADOverDHCPEnabled);
1520
0
    return mPACMan->LoadPACFromURI(spec);
1521
0
}
1522
1523
void
1524
nsProtocolProxyService::ProcessPACString(const nsCString &pacString,
1525
                                         uint32_t aResolveFlags,
1526
                                         nsIProxyInfo **result)
1527
0
{
1528
0
    if (pacString.IsEmpty()) {
1529
0
        *result = nullptr;
1530
0
        return;
1531
0
    }
1532
0
1533
0
    const char *proxies = pacString.get();
1534
0
1535
0
    nsProxyInfo *pi = nullptr, *first = nullptr, *last = nullptr;
1536
0
    while (*proxies) {
1537
0
        proxies = ExtractProxyInfo(proxies, aResolveFlags, &pi);
1538
0
        if (pi && (pi->mType == kProxyType_HTTPS) && !mProxyOverTLS) {
1539
0
            delete pi;
1540
0
            pi = nullptr;
1541
0
        }
1542
0
1543
0
        if (pi) {
1544
0
            if (last) {
1545
0
                NS_ASSERTION(last->mNext == nullptr, "leaking nsProxyInfo");
1546
0
                last->mNext = pi;
1547
0
            }
1548
0
            else
1549
0
                first = pi;
1550
0
            last = pi;
1551
0
        }
1552
0
    }
1553
0
    *result = first;
1554
0
}
1555
1556
// nsIProtocolProxyService2
1557
NS_IMETHODIMP
1558
nsProtocolProxyService::ReloadPAC()
1559
0
{
1560
0
    nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
1561
0
    if (!prefs)
1562
0
        return NS_OK;
1563
0
1564
0
    int32_t type;
1565
0
    nsresult rv = prefs->GetIntPref(PROXY_PREF("type"), &type);
1566
0
    if (NS_FAILED(rv))
1567
0
        return NS_OK;
1568
0
1569
0
    nsAutoCString pacSpec;
1570
0
    if (type == PROXYCONFIG_PAC)
1571
0
        prefs->GetCharPref(PROXY_PREF("autoconfig_url"), pacSpec);
1572
0
    else if (type == PROXYCONFIG_SYSTEM) {
1573
0
        if (mSystemProxySettings) {
1574
0
            AsyncConfigureFromPAC(true, true);
1575
0
        } else {
1576
0
            ResetPACThread();
1577
0
        }
1578
0
    }
1579
0
1580
0
    if (!pacSpec.IsEmpty() || type == PROXYCONFIG_WPAD)
1581
0
        ConfigureFromPAC(pacSpec, true);
1582
0
    return NS_OK;
1583
0
}
1584
1585
// When sync interface is removed this can go away too
1586
// The nsPACManCallback portion of this implementation should be run
1587
// off the main thread, because it uses a condvar for signaling and
1588
// the main thread is blocking on that condvar -
1589
//  so call nsPACMan::AsyncGetProxyForURI() with
1590
// a false mainThreadResponse parameter.
1591
class nsAsyncBridgeRequest final  : public nsPACManCallback
1592
{
1593
    NS_DECL_THREADSAFE_ISUPPORTS
1594
1595
     nsAsyncBridgeRequest()
1596
        : mMutex("nsDeprecatedCallback")
1597
        , mCondVar(mMutex, "nsDeprecatedCallback")
1598
        , mStatus(NS_OK)
1599
        , mCompleted(false)
1600
0
    {
1601
0
    }
1602
1603
    void OnQueryComplete(nsresult status,
1604
                          const nsACString &pacString,
1605
                          const nsACString &newPACURL) override
1606
0
    {
1607
0
        MutexAutoLock lock(mMutex);
1608
0
        mCompleted = true;
1609
0
        mStatus = status;
1610
0
        mPACString = pacString;
1611
0
        mPACURL = newPACURL;
1612
0
        mCondVar.Notify();
1613
0
    }
1614
1615
0
    void Lock()   { mMutex.Lock(); }
1616
0
    void Unlock() { mMutex.Unlock(); }
1617
0
    void Wait()   { mCondVar.Wait(TimeDuration::FromSeconds(3)); }
1618
1619
private:
1620
0
    ~nsAsyncBridgeRequest() = default;
1621
1622
    friend class nsProtocolProxyService;
1623
1624
    Mutex    mMutex;
1625
    CondVar  mCondVar;
1626
1627
    nsresult  mStatus;
1628
    nsCString mPACString;
1629
    nsCString mPACURL;
1630
    bool      mCompleted;
1631
};
1632
NS_IMPL_ISUPPORTS0(nsAsyncBridgeRequest)
1633
1634
nsresult
1635
nsProtocolProxyService::AsyncResolveInternal(nsIChannel *channel, uint32_t flags,
1636
                                             nsIProtocolProxyCallback *callback,
1637
                                             nsICancelable **result,
1638
                                             bool isSyncOK,
1639
                                             nsIEventTarget *mainThreadEventTarget)
1640
0
{
1641
0
    NS_ENSURE_ARG_POINTER(channel);
1642
0
    NS_ENSURE_ARG_POINTER(callback);
1643
0
1644
0
    nsCOMPtr<nsIURI> uri;
1645
0
    nsresult rv = GetProxyURI(channel, getter_AddRefs(uri));
1646
0
    if (NS_FAILED(rv)) return rv;
1647
0
1648
0
    *result = nullptr;
1649
0
    RefPtr<nsAsyncResolveRequest> ctx =
1650
0
        new nsAsyncResolveRequest(this, channel, flags, callback);
1651
0
1652
0
    nsProtocolInfo info;
1653
0
    rv = GetProtocolInfo(uri, &info);
1654
0
    if (NS_FAILED(rv))
1655
0
        return rv;
1656
0
1657
0
    nsCOMPtr<nsIProxyInfo> pi;
1658
0
    bool usePACThread;
1659
0
1660
0
    // adapt to realtime changes in the system proxy service
1661
0
    if (mProxyConfig == PROXYCONFIG_SYSTEM) {
1662
0
        nsCOMPtr<nsISystemProxySettings> sp2 =
1663
0
            do_GetService(NS_SYSTEMPROXYSETTINGS_CONTRACTID);
1664
0
        if (sp2 != mSystemProxySettings) {
1665
0
            mSystemProxySettings = sp2;
1666
0
            ResetPACThread();
1667
0
        }
1668
0
    }
1669
0
1670
0
    rv = SetupPACThread(mainThreadEventTarget);
1671
0
    if (NS_FAILED(rv)) {
1672
0
        return rv;
1673
0
    }
1674
0
1675
0
    // SystemProxySettings and PAC files can block the main thread
1676
0
    // but if neither of them are in use, we can just do the work
1677
0
    // right here and directly invoke the callback
1678
0
1679
0
    rv = Resolve_Internal(channel, info, flags,
1680
0
                          &usePACThread, getter_AddRefs(pi));
1681
0
    if (NS_FAILED(rv))
1682
0
        return rv;
1683
0
1684
0
    if (!usePACThread || !mPACMan) {
1685
0
        // we can do it locally
1686
0
        rv = ctx->ProcessLocally(info, pi, isSyncOK);
1687
0
        if (NS_SUCCEEDED(rv) && !isSyncOK) {
1688
0
            ctx.forget(result);
1689
0
        }
1690
0
        return rv;
1691
0
    }
1692
0
1693
0
    // else kick off a PAC thread query
1694
0
1695
0
    rv = mPACMan->AsyncGetProxyForURI(uri, ctx, true);
1696
0
    if (NS_SUCCEEDED(rv))
1697
0
        ctx.forget(result);
1698
0
    return rv;
1699
0
}
1700
1701
// nsIProtocolProxyService
1702
NS_IMETHODIMP
1703
nsProtocolProxyService::AsyncResolve2(nsIChannel *channel, uint32_t flags,
1704
                                      nsIProtocolProxyCallback *callback,
1705
                                      nsIEventTarget *mainThreadEventTarget,
1706
                                      nsICancelable **result)
1707
0
{
1708
0
    return AsyncResolveInternal(channel, flags, callback,
1709
0
                                result, true, mainThreadEventTarget);
1710
0
}
1711
1712
NS_IMETHODIMP
1713
nsProtocolProxyService::AsyncResolve(nsISupports *channelOrURI, uint32_t flags,
1714
                                     nsIProtocolProxyCallback *callback,
1715
                                     nsIEventTarget *mainThreadEventTarget,
1716
                                     nsICancelable **result)
1717
0
{
1718
0
1719
0
    nsresult rv;
1720
0
    // Check if we got a channel:
1721
0
    nsCOMPtr<nsIChannel> channel = do_QueryInterface(channelOrURI);
1722
0
    if (!channel) {
1723
0
        nsCOMPtr<nsIURI> uri = do_QueryInterface(channelOrURI);
1724
0
        if (!uri) {
1725
0
            return NS_ERROR_NO_INTERFACE;
1726
0
        }
1727
0
1728
0
        // creating a temporary channel from the URI which is not
1729
0
        // used to perform any network loads, hence its safe to
1730
0
        // use systemPrincipal as the loadingPrincipal.
1731
0
        rv = NS_NewChannel(getter_AddRefs(channel),
1732
0
                           uri,
1733
0
                           nsContentUtils::GetSystemPrincipal(),
1734
0
                           nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL,
1735
0
                           nsIContentPolicy::TYPE_OTHER);
1736
0
        NS_ENSURE_SUCCESS(rv, rv);
1737
0
    }
1738
0
1739
0
    return AsyncResolveInternal(channel, flags, callback,
1740
0
                                result, false, mainThreadEventTarget);
1741
0
}
1742
1743
NS_IMETHODIMP
1744
nsProtocolProxyService::NewProxyInfo(const nsACString &aType,
1745
                                     const nsACString &aHost,
1746
                                     int32_t aPort,
1747
                                     uint32_t aFlags,
1748
                                     uint32_t aFailoverTimeout,
1749
                                     nsIProxyInfo *aFailoverProxy,
1750
                                     nsIProxyInfo **aResult)
1751
0
{
1752
0
    return NewProxyInfoWithAuth(aType, aHost, aPort,
1753
0
                                EmptyCString(), EmptyCString(),
1754
0
                                aFlags, aFailoverTimeout,
1755
0
                                aFailoverProxy, aResult);
1756
0
}
1757
1758
NS_IMETHODIMP
1759
nsProtocolProxyService::NewProxyInfoWithAuth(const nsACString &aType,
1760
                                             const nsACString &aHost,
1761
                                             int32_t aPort,
1762
                                             const nsACString &aUsername,
1763
                                             const nsACString &aPassword,
1764
                                             uint32_t aFlags,
1765
                                             uint32_t aFailoverTimeout,
1766
                                             nsIProxyInfo *aFailoverProxy,
1767
                                             nsIProxyInfo **aResult)
1768
0
{
1769
0
    static const char *types[] = {
1770
0
        kProxyType_HTTP,
1771
0
        kProxyType_HTTPS,
1772
0
        kProxyType_SOCKS,
1773
0
        kProxyType_SOCKS4,
1774
0
        kProxyType_DIRECT
1775
0
    };
1776
0
1777
0
    // resolve type; this allows us to avoid copying the type string into each
1778
0
    // proxy info instance.  we just reference the string literals directly :)
1779
0
    const char* type = nullptr;
1780
0
    for (auto& t : types) {
1781
0
      if (aType.LowerCaseEqualsASCII(t)) {
1782
0
        type = t;
1783
0
        break;
1784
0
      }
1785
0
    }
1786
0
    NS_ENSURE_TRUE(type, NS_ERROR_INVALID_ARG);
1787
0
1788
0
    // We have only implemented username/password for SOCKS proxies.
1789
0
    if ((!aUsername.IsEmpty() || !aPassword.IsEmpty()) &&
1790
0
        !aType.LowerCaseEqualsASCII(kProxyType_SOCKS) &&
1791
0
        !aType.LowerCaseEqualsASCII(kProxyType_SOCKS4)) {
1792
0
        return NS_ERROR_NOT_IMPLEMENTED;
1793
0
    }
1794
0
1795
0
    return NewProxyInfo_Internal(type, aHost, aPort,
1796
0
                                 aUsername, aPassword,
1797
0
                                 aFlags, aFailoverTimeout,
1798
0
                                 aFailoverProxy, 0, aResult);
1799
0
}
1800
1801
NS_IMETHODIMP
1802
nsProtocolProxyService::GetFailoverForProxy(nsIProxyInfo  *aProxy,
1803
                                            nsIURI        *aURI,
1804
                                            nsresult       aStatus,
1805
                                            nsIProxyInfo **aResult)
1806
0
{
1807
0
    // We only support failover when a PAC file is configured, either
1808
0
    // directly or via system settings
1809
0
    if (mProxyConfig != PROXYCONFIG_PAC && mProxyConfig != PROXYCONFIG_WPAD &&
1810
0
        mProxyConfig != PROXYCONFIG_SYSTEM)
1811
0
        return NS_ERROR_NOT_AVAILABLE;
1812
0
1813
0
    // Verify that |aProxy| is one of our nsProxyInfo objects.
1814
0
    nsCOMPtr<nsProxyInfo> pi = do_QueryInterface(aProxy);
1815
0
    NS_ENSURE_ARG(pi);
1816
0
    // OK, the QI checked out.  We can proceed.
1817
0
1818
0
    // Remember that this proxy is down.
1819
0
    DisableProxy(pi);
1820
0
1821
0
    // NOTE: At this point, we might want to prompt the user if we have
1822
0
    //       not already tried going DIRECT.  This is something that the
1823
0
    //       classic codebase supported; however, IE6 does not prompt.
1824
0
1825
0
    if (!pi->mNext)
1826
0
        return NS_ERROR_NOT_AVAILABLE;
1827
0
1828
0
    LOG(("PAC failover from %s %s:%d to %s %s:%d\n",
1829
0
        pi->mType, pi->mHost.get(), pi->mPort,
1830
0
        pi->mNext->mType, pi->mNext->mHost.get(), pi->mNext->mPort));
1831
0
1832
0
    NS_ADDREF(*aResult = pi->mNext);
1833
0
    return NS_OK;
1834
0
}
1835
1836
namespace { // anon
1837
1838
class ProxyFilterPositionComparator
1839
{
1840
  typedef RefPtr<nsProtocolProxyService::FilterLink> FilterLinkRef;
1841
public:
1842
0
  bool Equals(const FilterLinkRef& a, const FilterLinkRef& b) const {
1843
0
    return a->position == b->position;
1844
0
  }
1845
0
  bool LessThan(const FilterLinkRef& a, const FilterLinkRef& b) const {
1846
0
    return a->position < b->position;
1847
0
  }
1848
};
1849
1850
class ProxyFilterObjectComparator
1851
{
1852
  typedef RefPtr<nsProtocolProxyService::FilterLink> FilterLinkRef;
1853
public:
1854
0
  bool Equals(const FilterLinkRef& link, const nsISupports* obj) const {
1855
0
    return obj == nsCOMPtr<nsISupports>(do_QueryInterface(link->filter)) ||
1856
0
           obj == nsCOMPtr<nsISupports>(do_QueryInterface(link->channelFilter));
1857
0
  }
1858
};
1859
1860
} // anon
1861
1862
nsresult
1863
nsProtocolProxyService::InsertFilterLink(RefPtr<FilterLink>&& link)
1864
0
{
1865
0
    LOG(("nsProtocolProxyService::InsertFilterLink filter=%p", link.get()));
1866
0
1867
0
    if (mIsShutdown) {
1868
0
        return NS_ERROR_FAILURE;
1869
0
    }
1870
0
1871
0
    mFilters.AppendElement(link);
1872
0
    mFilters.Sort(ProxyFilterPositionComparator());
1873
0
    return NS_OK;
1874
0
}
1875
1876
NS_IMETHODIMP
1877
nsProtocolProxyService::RegisterFilter(nsIProtocolProxyFilter *filter,
1878
                                       uint32_t position)
1879
0
{
1880
0
    UnregisterFilter(filter); // remove this filter if we already have it
1881
0
1882
0
    RefPtr<FilterLink> link = new FilterLink(position, filter);
1883
0
    return InsertFilterLink(std::move(link));
1884
0
}
1885
1886
NS_IMETHODIMP
1887
nsProtocolProxyService::RegisterChannelFilter(nsIProtocolProxyChannelFilter *channelFilter,
1888
                                              uint32_t position)
1889
0
{
1890
0
    UnregisterChannelFilter(channelFilter);  // remove this filter if we already have it
1891
0
1892
0
    RefPtr<FilterLink> link = new FilterLink(position, channelFilter);
1893
0
    return InsertFilterLink(std::move(link));
1894
0
}
1895
1896
nsresult
1897
nsProtocolProxyService::RemoveFilterLink(nsISupports* givenObject)
1898
0
{
1899
0
    LOG(("nsProtocolProxyService::RemoveFilterLink target=%p", givenObject));
1900
0
1901
0
    return mFilters.RemoveElement(givenObject, ProxyFilterObjectComparator())
1902
0
      ? NS_OK : NS_ERROR_UNEXPECTED;
1903
0
}
1904
1905
NS_IMETHODIMP
1906
nsProtocolProxyService::UnregisterFilter(nsIProtocolProxyFilter *filter)
1907
0
{
1908
0
    // QI to nsISupports so we can safely test object identity.
1909
0
    nsCOMPtr<nsISupports> givenObject = do_QueryInterface(filter);
1910
0
    return RemoveFilterLink(givenObject);
1911
0
}
1912
1913
NS_IMETHODIMP
1914
nsProtocolProxyService::UnregisterChannelFilter(nsIProtocolProxyChannelFilter *channelFilter)
1915
0
{
1916
0
    // QI to nsISupports so we can safely test object identity.
1917
0
    nsCOMPtr<nsISupports> givenObject = do_QueryInterface(channelFilter);
1918
0
    return RemoveFilterLink(givenObject);
1919
0
}
1920
1921
NS_IMETHODIMP
1922
nsProtocolProxyService::GetProxyConfigType(uint32_t* aProxyConfigType)
1923
0
{
1924
0
  *aProxyConfigType = mProxyConfig;
1925
0
  return NS_OK;
1926
0
}
1927
1928
void
1929
nsProtocolProxyService::LoadHostFilters(const nsACString& aFilters)
1930
0
{
1931
0
    if (mIsShutdown) {
1932
0
        return;
1933
0
    }
1934
0
1935
0
    // check to see the owners flag? /!?/ TODO
1936
0
    if (mHostFiltersArray.Length() > 0) {
1937
0
        mHostFiltersArray.Clear();
1938
0
    }
1939
0
1940
0
    if (aFilters.IsEmpty()) {
1941
0
        return;
1942
0
    }
1943
0
1944
0
    //
1945
0
    // filter  = ( host | domain | ipaddr ["/" mask] ) [":" port]
1946
0
    // filters = filter *( "," LWS filter)
1947
0
    //
1948
0
    // Reset mFilterLocalHosts - will be set to true if "<local>" is in pref string
1949
0
    mFilterLocalHosts = false;
1950
0
1951
0
    mozilla::Tokenizer t(aFilters);
1952
0
    mozilla::Tokenizer::Token token;
1953
0
    bool eof = false;
1954
0
    // while (*filters) {
1955
0
    while (!eof) {
1956
0
        // skip over spaces and ,
1957
0
        t.SkipWhites();
1958
0
        while (t.CheckChar(',')) {
1959
0
            t.SkipWhites();
1960
0
        }
1961
0
1962
0
        nsAutoCString portStr;
1963
0
        nsAutoCString hostStr;
1964
0
        nsAutoCString maskStr;
1965
0
        t.Record();
1966
0
1967
0
        bool parsingIPv6 = false;
1968
0
        bool parsingPort = false;
1969
0
        bool parsingMask = false;
1970
0
        while (t.Next(token)) {
1971
0
            if (token.Equals(mozilla::Tokenizer::Token::EndOfFile()))  {
1972
0
                eof = true;
1973
0
                break;
1974
0
            }
1975
0
            if (token.Equals(mozilla::Tokenizer::Token::Char(',')) ||
1976
0
                token.Type() == mozilla::Tokenizer::TOKEN_WS) {
1977
0
                break;
1978
0
            }
1979
0
1980
0
            if (token.Equals(mozilla::Tokenizer::Token::Char('['))) {
1981
0
                parsingIPv6 = true;
1982
0
                continue;
1983
0
            }
1984
0
1985
0
            if (!parsingIPv6 && token.Equals(mozilla::Tokenizer::Token::Char(':'))) {
1986
0
                // Port is starting. Claim the previous as host.
1987
0
                if (parsingMask) {
1988
0
                    t.Claim(maskStr);
1989
0
                } else {
1990
0
                    t.Claim(hostStr);
1991
0
                }
1992
0
                t.Record();
1993
0
                parsingPort = true;
1994
0
                continue;
1995
0
            } else if (token.Equals(mozilla::Tokenizer::Token::Char('/'))) {
1996
0
                t.Claim(hostStr);
1997
0
                t.Record();
1998
0
                parsingMask = true;
1999
0
                continue;
2000
0
            } else if (token.Equals(mozilla::Tokenizer::Token::Char(']'))) {
2001
0
                parsingIPv6 = false;
2002
0
                continue;
2003
0
            }
2004
0
        }
2005
0
        if (!parsingPort && !parsingMask) {
2006
0
            t.Claim(hostStr);
2007
0
        } else if (parsingPort) {
2008
0
            t.Claim(portStr);
2009
0
        } else if (parsingMask) {
2010
0
            t.Claim(maskStr);
2011
0
        } else {
2012
0
            NS_WARNING("Could not parse this rule");
2013
0
            continue;
2014
0
        }
2015
0
2016
0
        if (hostStr.IsEmpty()) {
2017
0
            continue;
2018
0
        }
2019
0
2020
0
        // If the current host filter is "<local>", then all local (i.e.
2021
0
        // no dots in the hostname) hosts should bypass the proxy
2022
0
        if (hostStr.EqualsIgnoreCase("<local>")) {
2023
0
            mFilterLocalHosts = true;
2024
0
            LOG(("loaded filter for local hosts "
2025
0
                 "(plain host names, no dots)\n"));
2026
0
            // Continue to next host filter;
2027
0
            continue;
2028
0
        }
2029
0
2030
0
        // For all other host filters, create HostInfo object and add to list
2031
0
        HostInfo *hinfo = new HostInfo();
2032
0
        nsresult rv = NS_OK;
2033
0
2034
0
        int32_t port = portStr.ToInteger(&rv);
2035
0
        if (NS_FAILED(rv)) {
2036
0
            port = 0;
2037
0
        }
2038
0
        hinfo->port = port;
2039
0
2040
0
        int32_t maskLen = maskStr.ToInteger(&rv);
2041
0
        if (NS_FAILED(rv)) {
2042
0
            maskLen = 128;
2043
0
        }
2044
0
2045
0
        // PR_StringToNetAddr can't parse brackets enclosed IPv6
2046
0
        nsAutoCString addrString = hostStr;
2047
0
        if (hostStr.First() == '[' && hostStr.Last() == ']') {
2048
0
            addrString = Substring(hostStr, 1, hostStr.Length() - 2);
2049
0
        }
2050
0
2051
0
        PRNetAddr addr;
2052
0
        if (PR_StringToNetAddr(addrString.get(), &addr) == PR_SUCCESS) {
2053
0
            hinfo->is_ipaddr   = true;
2054
0
            hinfo->ip.family   = PR_AF_INET6; // we always store address as IPv6
2055
0
            hinfo->ip.mask_len = maskLen;
2056
0
2057
0
            if (hinfo->ip.mask_len == 0) {
2058
0
                NS_WARNING("invalid mask");
2059
0
                goto loser;
2060
0
            }
2061
0
2062
0
            if (addr.raw.family == PR_AF_INET) {
2063
0
                // convert to IPv4-mapped address
2064
0
                PR_ConvertIPv4AddrToIPv6(addr.inet.ip, &hinfo->ip.addr);
2065
0
                // adjust mask_len accordingly
2066
0
                if (hinfo->ip.mask_len <= 32)
2067
0
                    hinfo->ip.mask_len += 96;
2068
0
            }
2069
0
            else if (addr.raw.family == PR_AF_INET6) {
2070
0
                // copy the address
2071
0
                memcpy(&hinfo->ip.addr, &addr.ipv6.ip, sizeof(PRIPv6Addr));
2072
0
            }
2073
0
            else {
2074
0
                NS_WARNING("unknown address family");
2075
0
                goto loser;
2076
0
            }
2077
0
2078
0
            // apply mask to IPv6 address
2079
0
            proxy_MaskIPv6Addr(hinfo->ip.addr, hinfo->ip.mask_len);
2080
0
        }
2081
0
        else {
2082
0
            nsAutoCString host;
2083
0
            if (hostStr.First() == '*') {
2084
0
                host = Substring(hostStr, 1);
2085
0
            } else {
2086
0
                host = hostStr;
2087
0
            }
2088
0
2089
0
            if (host.IsEmpty()) {
2090
0
                hinfo->name.host = nullptr;
2091
0
                goto loser;
2092
0
            }
2093
0
2094
0
            hinfo->name.host_len = host.Length();
2095
0
2096
0
            hinfo->is_ipaddr = false;
2097
0
            hinfo->name.host = ToNewCString(host);
2098
0
2099
0
            if (!hinfo->name.host)
2100
0
                goto loser;
2101
0
        }
2102
0
2103
0
//#define DEBUG_DUMP_FILTERS
2104
#ifdef DEBUG_DUMP_FILTERS
2105
        printf("loaded filter[%zu]:\n", mHostFiltersArray.Length());
2106
        printf("  is_ipaddr = %u\n", hinfo->is_ipaddr);
2107
        printf("  port = %u\n", hinfo->port);
2108
        printf("  host = %s\n", hostStr.get());
2109
        if (hinfo->is_ipaddr) {
2110
            printf("  ip.family = %x\n", hinfo->ip.family);
2111
            printf("  ip.mask_len = %u\n", hinfo->ip.mask_len);
2112
2113
            PRNetAddr netAddr;
2114
            PR_SetNetAddr(PR_IpAddrNull, PR_AF_INET6, 0, &netAddr);
2115
            memcpy(&netAddr.ipv6.ip, &hinfo->ip.addr, sizeof(hinfo->ip.addr));
2116
2117
            char buf[256];
2118
            PR_NetAddrToString(&netAddr, buf, sizeof(buf));
2119
2120
            printf("  ip.addr = %s\n", buf);
2121
        }
2122
        else {
2123
            printf("  name.host = %s\n", hinfo->name.host);
2124
        }
2125
#endif
2126
2127
0
        mHostFiltersArray.AppendElement(hinfo);
2128
0
        hinfo = nullptr;
2129
0
loser:
2130
0
        delete hinfo;
2131
0
    }
2132
0
}
2133
2134
nsresult
2135
nsProtocolProxyService::GetProtocolInfo(nsIURI *uri, nsProtocolInfo *info)
2136
0
{
2137
0
    MOZ_ASSERT(uri, "URI is null");
2138
0
    MOZ_ASSERT(info, "info is null");
2139
0
2140
0
    nsresult rv;
2141
0
2142
0
    rv = uri->GetScheme(info->scheme);
2143
0
    if (NS_FAILED(rv))
2144
0
        return rv;
2145
0
2146
0
    nsCOMPtr<nsIIOService> ios = do_GetIOService(&rv);
2147
0
    if (NS_FAILED(rv))
2148
0
        return rv;
2149
0
2150
0
    nsCOMPtr<nsIProtocolHandler> handler;
2151
0
    rv = ios->GetProtocolHandler(info->scheme.get(), getter_AddRefs(handler));
2152
0
    if (NS_FAILED(rv))
2153
0
        return rv;
2154
0
2155
0
    rv = handler->DoGetProtocolFlags(uri, &info->flags);
2156
0
    if (NS_FAILED(rv))
2157
0
        return rv;
2158
0
2159
0
    rv = handler->GetDefaultPort(&info->defaultPort);
2160
0
    return rv;
2161
0
}
2162
2163
nsresult
2164
nsProtocolProxyService::NewProxyInfo_Internal(const char *aType,
2165
                                              const nsACString &aHost,
2166
                                              int32_t aPort,
2167
                                              const nsACString &aUsername,
2168
                                              const nsACString &aPassword,
2169
                                              uint32_t aFlags,
2170
                                              uint32_t aFailoverTimeout,
2171
                                              nsIProxyInfo *aFailoverProxy,
2172
                                              uint32_t aResolveFlags,
2173
                                              nsIProxyInfo **aResult)
2174
0
{
2175
0
    if (aPort <= 0)
2176
0
        aPort = -1;
2177
0
2178
0
    nsCOMPtr<nsProxyInfo> failover;
2179
0
    if (aFailoverProxy) {
2180
0
        failover = do_QueryInterface(aFailoverProxy);
2181
0
        NS_ENSURE_ARG(failover);
2182
0
    }
2183
0
2184
0
    nsProxyInfo *proxyInfo = new nsProxyInfo();
2185
0
    if (!proxyInfo)
2186
0
        return NS_ERROR_OUT_OF_MEMORY;
2187
0
2188
0
    proxyInfo->mType = aType;
2189
0
    proxyInfo->mHost = aHost;
2190
0
    proxyInfo->mPort = aPort;
2191
0
    proxyInfo->mUsername = aUsername;
2192
0
    proxyInfo->mPassword = aPassword;
2193
0
    proxyInfo->mFlags = aFlags;
2194
0
    proxyInfo->mResolveFlags = aResolveFlags;
2195
0
    proxyInfo->mTimeout = aFailoverTimeout == UINT32_MAX
2196
0
        ? mFailedProxyTimeout : aFailoverTimeout;
2197
0
    failover.swap(proxyInfo->mNext);
2198
0
2199
0
    NS_ADDREF(*aResult = proxyInfo);
2200
0
    return NS_OK;
2201
0
}
2202
2203
nsresult
2204
nsProtocolProxyService::Resolve_Internal(nsIChannel *channel,
2205
                                         const nsProtocolInfo &info,
2206
                                         uint32_t flags,
2207
                                         bool *usePACThread,
2208
                                         nsIProxyInfo **result)
2209
0
{
2210
0
    NS_ENSURE_ARG_POINTER(channel);
2211
0
2212
0
    *usePACThread = false;
2213
0
    *result = nullptr;
2214
0
2215
0
    if (!(info.flags & nsIProtocolHandler::ALLOWS_PROXY))
2216
0
        return NS_OK;  // Can't proxy this (filters may not override)
2217
0
2218
0
    nsCOMPtr<nsIURI> uri;
2219
0
    nsresult rv = GetProxyURI(channel, getter_AddRefs(uri));
2220
0
    if (NS_FAILED(rv)) return rv;
2221
0
2222
0
    // See bug #586908.
2223
0
    // Avoid endless loop if |uri| is the current PAC-URI. Returning OK
2224
0
    // here means that we will not use a proxy for this connection.
2225
0
    if (mPACMan && mPACMan->IsPACURI(uri))
2226
0
        return NS_OK;
2227
0
2228
0
    bool mainThreadOnly;
2229
0
    if (mSystemProxySettings &&
2230
0
        mProxyConfig == PROXYCONFIG_SYSTEM &&
2231
0
        NS_SUCCEEDED(mSystemProxySettings->GetMainThreadOnly(&mainThreadOnly)) &&
2232
0
        !mainThreadOnly) {
2233
0
        *usePACThread = true;
2234
0
        return NS_OK;
2235
0
    }
2236
0
2237
0
    if (mSystemProxySettings && mProxyConfig == PROXYCONFIG_SYSTEM) {
2238
0
        // If the system proxy setting implementation is not threadsafe (e.g
2239
0
        // linux gconf), we'll do it inline here. Such implementations promise
2240
0
        // not to block
2241
0
        // bug 1366133: this block uses GetPACURI & GetProxyForURI, which may
2242
0
        // hang on Windows platform. Fortunately, current implementation on
2243
0
        // Windows is not main thread only, so we are safe here.
2244
0
2245
0
        nsAutoCString PACURI;
2246
0
        nsAutoCString pacString;
2247
0
2248
0
        if (NS_SUCCEEDED(mSystemProxySettings->GetPACURI(PACURI)) &&
2249
0
            !PACURI.IsEmpty()) {
2250
0
            // There is a PAC URI configured. If it is unchanged, then
2251
0
            // just execute the PAC thread. If it is changed then load
2252
0
            // the new value
2253
0
2254
0
            if (mPACMan && mPACMan->IsPACURI(PACURI)) {
2255
0
                // unchanged
2256
0
                *usePACThread = true;
2257
0
                return NS_OK;
2258
0
            }
2259
0
2260
0
            ConfigureFromPAC(PACURI, false);
2261
0
            return NS_OK;
2262
0
        }
2263
0
2264
0
        nsAutoCString spec;
2265
0
        nsAutoCString host;
2266
0
        nsAutoCString scheme;
2267
0
        int32_t port = -1;
2268
0
2269
0
        uri->GetAsciiSpec(spec);
2270
0
        uri->GetAsciiHost(host);
2271
0
        uri->GetScheme(scheme);
2272
0
        uri->GetPort(&port);
2273
0
2274
0
        if (flags & RESOLVE_PREFER_SOCKS_PROXY) {
2275
0
            LOG(("Ignoring RESOLVE_PREFER_SOCKS_PROXY for system proxy setting\n"));
2276
0
        } else if (flags & RESOLVE_PREFER_HTTPS_PROXY) {
2277
0
            scheme.AssignLiteral("https");
2278
0
        } else if (flags & RESOLVE_IGNORE_URI_SCHEME) {
2279
0
            scheme.AssignLiteral("http");
2280
0
        }
2281
0
2282
0
        // now try the system proxy settings for this particular url
2283
0
        if (NS_SUCCEEDED(mSystemProxySettings->
2284
0
                         GetProxyForURI(spec, scheme, host, port,
2285
0
                                        pacString))) {
2286
0
            ProcessPACString(pacString, 0, result);
2287
0
            return NS_OK;
2288
0
        }
2289
0
    }
2290
0
2291
0
    // if proxies are enabled and this host:port combo is supposed to use a
2292
0
    // proxy, check for a proxy.
2293
0
    if (mProxyConfig == PROXYCONFIG_DIRECT ||
2294
0
        (mProxyConfig == PROXYCONFIG_MANUAL &&
2295
0
         !CanUseProxy(uri, info.defaultPort)))
2296
0
        return NS_OK;
2297
0
2298
0
    // Proxy auto config magic...
2299
0
    if (mProxyConfig == PROXYCONFIG_PAC || mProxyConfig == PROXYCONFIG_WPAD) {
2300
0
        // Do not query PAC now.
2301
0
        *usePACThread = true;
2302
0
        return NS_OK;
2303
0
    }
2304
0
2305
0
    // If we aren't in manual proxy configuration mode then we don't
2306
0
    // want to honor any manual specific prefs that might be still set
2307
0
    if (mProxyConfig != PROXYCONFIG_MANUAL)
2308
0
        return NS_OK;
2309
0
2310
0
    // proxy info values for manual configuration mode
2311
0
    const char *type = nullptr;
2312
0
    const nsACString *host = nullptr;
2313
0
    int32_t port = -1;
2314
0
2315
0
    uint32_t proxyFlags = 0;
2316
0
2317
0
    if ((flags & RESOLVE_PREFER_SOCKS_PROXY) &&
2318
0
        !mSOCKSProxyTarget.IsEmpty() &&
2319
0
        (IsHostLocalTarget(mSOCKSProxyTarget) || mSOCKSProxyPort > 0)) {
2320
0
      host = &mSOCKSProxyTarget;
2321
0
      if (mSOCKSProxyVersion == 4)
2322
0
          type = kProxyType_SOCKS4;
2323
0
      else
2324
0
          type = kProxyType_SOCKS;
2325
0
      port = mSOCKSProxyPort;
2326
0
      if (mSOCKSProxyRemoteDNS)
2327
0
          proxyFlags |= nsIProxyInfo::TRANSPARENT_PROXY_RESOLVES_HOST;
2328
0
    }
2329
0
    else if ((flags & RESOLVE_PREFER_HTTPS_PROXY) &&
2330
0
             !mHTTPSProxyHost.IsEmpty() && mHTTPSProxyPort > 0) {
2331
0
        host = &mHTTPSProxyHost;
2332
0
        type = kProxyType_HTTP;
2333
0
        port = mHTTPSProxyPort;
2334
0
    }
2335
0
    else if (!mHTTPProxyHost.IsEmpty() && mHTTPProxyPort > 0 &&
2336
0
             ((flags & RESOLVE_IGNORE_URI_SCHEME) ||
2337
0
              info.scheme.EqualsLiteral("http"))) {
2338
0
        host = &mHTTPProxyHost;
2339
0
        type = kProxyType_HTTP;
2340
0
        port = mHTTPProxyPort;
2341
0
    }
2342
0
    else if (!mHTTPSProxyHost.IsEmpty() && mHTTPSProxyPort > 0 &&
2343
0
             !(flags & RESOLVE_IGNORE_URI_SCHEME) &&
2344
0
             info.scheme.EqualsLiteral("https")) {
2345
0
        host = &mHTTPSProxyHost;
2346
0
        type = kProxyType_HTTP;
2347
0
        port = mHTTPSProxyPort;
2348
0
    }
2349
0
    else if (!mFTPProxyHost.IsEmpty() && mFTPProxyPort > 0 &&
2350
0
             !(flags & RESOLVE_IGNORE_URI_SCHEME) &&
2351
0
             info.scheme.EqualsLiteral("ftp")) {
2352
0
        host = &mFTPProxyHost;
2353
0
        type = kProxyType_HTTP;
2354
0
        port = mFTPProxyPort;
2355
0
    }
2356
0
    else if (!mSOCKSProxyTarget.IsEmpty() &&
2357
0
        (IsHostLocalTarget(mSOCKSProxyTarget) || mSOCKSProxyPort > 0)) {
2358
0
        host = &mSOCKSProxyTarget;
2359
0
        if (mSOCKSProxyVersion == 4)
2360
0
            type = kProxyType_SOCKS4;
2361
0
        else
2362
0
            type = kProxyType_SOCKS;
2363
0
        port = mSOCKSProxyPort;
2364
0
        if (mSOCKSProxyRemoteDNS)
2365
0
            proxyFlags |= nsIProxyInfo::TRANSPARENT_PROXY_RESOLVES_HOST;
2366
0
    }
2367
0
2368
0
    if (type) {
2369
0
        rv = NewProxyInfo_Internal(type, *host, port,
2370
0
                                   EmptyCString(), EmptyCString(),
2371
0
                                   proxyFlags, UINT32_MAX, nullptr, flags,
2372
0
                                   result);
2373
0
        if (NS_FAILED(rv))
2374
0
            return rv;
2375
0
    }
2376
0
2377
0
    return NS_OK;
2378
0
}
2379
2380
void
2381
nsProtocolProxyService::MaybeDisableDNSPrefetch(nsIProxyInfo *aProxy)
2382
0
{
2383
0
    // Disable Prefetch in the DNS service if a proxy is in use.
2384
0
    if (!aProxy)
2385
0
        return;
2386
0
2387
0
    nsCOMPtr<nsProxyInfo> pi = do_QueryInterface(aProxy);
2388
0
    if (!pi ||
2389
0
        !pi->mType ||
2390
0
        pi->mType == kProxyType_DIRECT)
2391
0
        return;
2392
0
2393
0
    nsCOMPtr<nsIDNSService> dns = do_GetService(NS_DNSSERVICE_CONTRACTID);
2394
0
    if (!dns)
2395
0
        return;
2396
0
    nsCOMPtr<nsPIDNSService> pdns = do_QueryInterface(dns);
2397
0
    if (!pdns)
2398
0
        return;
2399
0
2400
0
    // We lose the prefetch optimization for the life of the dns service.
2401
0
    pdns->SetPrefetchEnabled(false);
2402
0
}
2403
2404
void
2405
nsProtocolProxyService::CopyFilters(nsTArray<RefPtr<FilterLink>>& aCopy)
2406
0
{
2407
0
    MOZ_ASSERT(aCopy.Length() == 0);
2408
0
    aCopy.AppendElements(mFilters);
2409
0
}
2410
2411
bool
2412
nsProtocolProxyService::ApplyFilter(FilterLink const* filterLink,
2413
                                    nsIChannel *channel,
2414
                                    const nsProtocolInfo &info,
2415
                                    nsCOMPtr<nsIProxyInfo> list,
2416
                                    nsIProxyProtocolFilterResult* callback)
2417
0
{
2418
0
    nsresult rv;
2419
0
2420
0
    // We prune the proxy list prior to invoking each filter.  This may be
2421
0
    // somewhat inefficient, but it seems like a good idea since we want each
2422
0
    // filter to "see" a valid proxy list.
2423
0
    PruneProxyInfo(info, list);
2424
0
2425
0
    if (filterLink->filter) {
2426
0
      nsCOMPtr<nsIURI> uri;
2427
0
      Unused << GetProxyURI(channel, getter_AddRefs(uri));
2428
0
      if (!uri) {
2429
0
        return false;
2430
0
      }
2431
0
2432
0
      rv = filterLink->filter->ApplyFilter(this, uri, list, callback);
2433
0
      return NS_SUCCEEDED(rv);
2434
0
    }
2435
0
2436
0
    if (filterLink->channelFilter) {
2437
0
      rv = filterLink->channelFilter->ApplyFilter(this, channel, list, callback);
2438
0
      return NS_SUCCEEDED(rv);
2439
0
    }
2440
0
2441
0
    return false;
2442
0
}
2443
2444
void
2445
nsProtocolProxyService::PruneProxyInfo(const nsProtocolInfo &info,
2446
                                       nsIProxyInfo **list)
2447
0
{
2448
0
    if (!*list)
2449
0
        return;
2450
0
2451
0
    LOG(("nsProtocolProxyService::PruneProxyInfo ENTER list=%p", *list));
2452
0
2453
0
    nsProxyInfo *head = nullptr;
2454
0
    CallQueryInterface(*list, &head);
2455
0
    if (!head) {
2456
0
        MOZ_ASSERT_UNREACHABLE("nsIProxyInfo must QI to nsProxyInfo");
2457
0
        return;
2458
0
    }
2459
0
    NS_RELEASE(*list);
2460
0
2461
0
    // Pruning of disabled proxies works like this:
2462
0
    //   - If all proxies are disabled, return the full list
2463
0
    //   - Otherwise, remove the disabled proxies.
2464
0
    //
2465
0
    // Pruning of disallowed proxies works like this:
2466
0
    //   - If the protocol handler disallows the proxy, then we disallow it.
2467
0
2468
0
    // Start by removing all disallowed proxies if required:
2469
0
    if (!(info.flags & nsIProtocolHandler::ALLOWS_PROXY_HTTP)) {
2470
0
        nsProxyInfo *last = nullptr, *iter = head;
2471
0
        while (iter) {
2472
0
            if ((iter->Type() == kProxyType_HTTP) ||
2473
0
                (iter->Type() == kProxyType_HTTPS)) {
2474
0
                // reject!
2475
0
                if (last)
2476
0
                    last->mNext = iter->mNext;
2477
0
                else
2478
0
                    head = iter->mNext;
2479
0
                nsProxyInfo *next = iter->mNext;
2480
0
                iter->mNext = nullptr;
2481
0
                iter->Release();
2482
0
                iter = next;
2483
0
            } else {
2484
0
                last = iter;
2485
0
                iter = iter->mNext;
2486
0
            }
2487
0
        }
2488
0
        if (!head) {
2489
0
            return;
2490
0
        }
2491
0
    }
2492
0
2493
0
    // Now, scan to see if all remaining proxies are disabled.  If so, then
2494
0
    // we'll just bail and return them all.  Otherwise, we'll go and prune the
2495
0
    // disabled ones.
2496
0
2497
0
    bool allDisabled = true;
2498
0
2499
0
    nsProxyInfo *iter;
2500
0
    for (iter = head; iter; iter = iter->mNext) {
2501
0
        if (!IsProxyDisabled(iter)) {
2502
0
            allDisabled = false;
2503
0
            break;
2504
0
        }
2505
0
    }
2506
0
2507
0
    if (allDisabled) {
2508
0
        LOG(("All proxies are disabled, so trying all again"));
2509
0
    } else {
2510
0
        // remove any disabled proxies.
2511
0
        nsProxyInfo *last = nullptr;
2512
0
        for (iter = head; iter; ) {
2513
0
            if (IsProxyDisabled(iter)) {
2514
0
                // reject!
2515
0
                nsProxyInfo *reject = iter;
2516
0
2517
0
                iter = iter->mNext;
2518
0
                if (last)
2519
0
                    last->mNext = iter;
2520
0
                else
2521
0
                    head = iter;
2522
0
2523
0
                reject->mNext = nullptr;
2524
0
                NS_RELEASE(reject);
2525
0
                continue;
2526
0
            }
2527
0
2528
0
            // since we are about to use this proxy, make sure it is not on
2529
0
            // the disabled proxy list.  we'll add it back to that list if
2530
0
            // we have to (in GetFailoverForProxy).
2531
0
            //
2532
0
            // XXX(darin): It might be better to do this as a final pass.
2533
0
            //
2534
0
            EnableProxy(iter);
2535
0
2536
0
            last = iter;
2537
0
            iter = iter->mNext;
2538
0
        }
2539
0
    }
2540
0
2541
0
    // if only DIRECT was specified then return no proxy info, and we're done.
2542
0
    if (head && !head->mNext && head->mType == kProxyType_DIRECT)
2543
0
        NS_RELEASE(head);
2544
0
2545
0
    *list = head;  // Transfer ownership
2546
0
2547
0
    LOG(("nsProtocolProxyService::PruneProxyInfo LEAVE list=%p", *list));
2548
0
}
2549
2550
} // namespace net
2551
} // namespace mozilla