summaryrefslogtreecommitdiffstats
path: root/netwerk/protocol/http/HttpWinUtils.cpp
blob: b566cdc4f6b01b71146546110359a4845dd684f8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#include "HttpWinUtils.h"
#include "nsIURI.h"
#include "nsHttpChannel.h"
#include "mozilla/ClearOnShutdown.h"
#include <proofofpossessioncookieinfo.h>

namespace mozilla {
namespace net {

static StaticRefPtr<IProofOfPossessionCookieInfoManager> sPopCookieManager;
static bool sPopCookieManagerAvailable = true;

void AddWindowsSSO(nsHttpChannel* channel) {
  if (!sPopCookieManagerAvailable) {
    return;
  }
  HRESULT hr;
  if (!sPopCookieManager) {
    GUID CLSID_ProofOfPossessionCookieInfoManager;
    GUID IID_IProofOfPossessionCookieInfoManager;

    CLSIDFromString(L"{A9927F85-A304-4390-8B23-A75F1C668600}",
                    &CLSID_ProofOfPossessionCookieInfoManager);
    IIDFromString(L"{CDAECE56-4EDF-43DF-B113-88E4556FA1BB}",
                  &IID_IProofOfPossessionCookieInfoManager);

    hr = CoCreateInstance(CLSID_ProofOfPossessionCookieInfoManager, NULL,
                          CLSCTX_INPROC_SERVER,
                          IID_IProofOfPossessionCookieInfoManager,
                          reinterpret_cast<void**>(&sPopCookieManager));
    if (FAILED(hr)) {
      sPopCookieManagerAvailable = false;
      return;
    }

    RunOnShutdown([&] {
      if (sPopCookieManager) {
        sPopCookieManager = nullptr;
      }
    });
  }

  DWORD cookieCount = 0;
  ProofOfPossessionCookieInfo* cookieInfo = nullptr;

  nsCOMPtr<nsIURI> uri;
  channel->GetURI(getter_AddRefs(uri));

  nsAutoCString urispec;
  uri->GetSpec(urispec);

  hr = sPopCookieManager->GetCookieInfoForUri(
      NS_ConvertUTF8toUTF16(urispec).get(), &cookieCount, &cookieInfo);
  if (FAILED(hr)) {
    return;
  }

  nsAutoCString host;
  uri->GetHost(host);
  bool addCookies = false;
  if (StringEndsWith(host, ".live.com"_ns)) {
    addCookies = true;
  }

  nsAutoString allCookies;

  for (DWORD i = 0; i < cookieCount; i++) {
    nsAutoString cookieData;
    cookieData.Assign(cookieInfo[i].data);
    // Strip old Set-Cookie info for WinInet
    int32_t semicolon = cookieData.FindChar(';');
    if (semicolon >= 0) {
      cookieData.SetLength(semicolon);
    }
    if (StringBeginsWith(nsDependentString(cookieInfo[i].name), u"x-ms-"_ns)) {
      channel->SetRequestHeader(NS_ConvertUTF16toUTF8(cookieInfo[i].name),
                                NS_ConvertUTF16toUTF8(cookieData),
                                true /* merge */);
    } else if (addCookies) {
      if (!allCookies.IsEmpty()) {
        allCookies.AppendLiteral("; ");
      }
      allCookies.Append(cookieInfo[i].name);
      allCookies.AppendLiteral("=");
      allCookies.Append(cookieData);
    }
  }

  // Merging cookie headers doesn't work correctly as it separates the new
  // cookies using commas instead of semicolons, so we have to replace
  // the entire header.
  if (!allCookies.IsEmpty()) {
    nsAutoCString cookieHeader;
    channel->GetRequestHeader(nsHttp::Cookie.val(), cookieHeader);
    if (!cookieHeader.IsEmpty()) {
      cookieHeader.AppendLiteral("; ");
    }
    cookieHeader.Append(NS_ConvertUTF16toUTF8(allCookies));
    channel->SetRequestHeader(nsHttp::Cookie.val(), cookieHeader, false);
  }
  if (cookieInfo) {
    FreeProofOfPossessionCookieInfoArray(cookieInfo, cookieCount);
  }
}

}  // namespace net
}  // namespace mozilla