Blob Blame History Raw
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef nsHttpAuthCache_h__
#define nsHttpAuthCache_h__

#include "nsError.h"
#include "nsTArray.h"
#include "nsAutoPtr.h"
#include "nsClassHashtable.h"
#include "nsCOMPtr.h"
#include "nsHashKeys.h"
#include "nsStringFwd.h"
#include "nsIObserver.h"

namespace mozilla {

class OriginAttributesPattern;

namespace net {

struct nsHttpAuthPath {
  struct nsHttpAuthPath *mNext;
  char mPath[1];
};

//-----------------------------------------------------------------------------
// nsHttpAuthIdentity
//-----------------------------------------------------------------------------

class nsHttpAuthIdentity {
 public:
  nsHttpAuthIdentity() : mUser(nullptr), mPass(nullptr), mDomain(nullptr) {}
  nsHttpAuthIdentity(const char16_t *domain, const char16_t *user,
                     const char16_t *password)
      : mUser(nullptr) {
    DebugOnly<nsresult> rv = Set(domain, user, password);
    MOZ_ASSERT(NS_SUCCEEDED(rv));
  }
  ~nsHttpAuthIdentity() { Clear(); }

  const char16_t *Domain() const { return mDomain; }
  const char16_t *User() const { return mUser; }
  const char16_t *Password() const { return mPass; }

  MOZ_MUST_USE nsresult Set(const char16_t *domain, const char16_t *user,
                            const char16_t *password);
  MOZ_MUST_USE nsresult Set(const nsHttpAuthIdentity &other) {
    return Set(other.mDomain, other.mUser, other.mPass);
  }
  void Clear();

  bool Equals(const nsHttpAuthIdentity &other) const;
  bool IsEmpty() const { return !mUser; }

 private:
  // allocated as one contiguous blob, starting at mUser.
  char16_t *mUser;
  char16_t *mPass;
  char16_t *mDomain;
};

//-----------------------------------------------------------------------------
// nsHttpAuthEntry
//-----------------------------------------------------------------------------

class nsHttpAuthEntry {
 public:
  const char *Realm() const { return mRealm; }
  const char *Creds() const { return mCreds; }
  const char *Challenge() const { return mChallenge; }
  const char16_t *Domain() const { return mIdent.Domain(); }
  const char16_t *User() const { return mIdent.User(); }
  const char16_t *Pass() const { return mIdent.Password(); }
  nsHttpAuthPath *RootPath() { return mRoot; }

  const nsHttpAuthIdentity &Identity() const { return mIdent; }

  MOZ_MUST_USE nsresult AddPath(const char *aPath);

  nsCOMPtr<nsISupports> mMetaData;

 private:
  nsHttpAuthEntry(const char *path, const char *realm, const char *creds,
                  const char *challenge, const nsHttpAuthIdentity *ident,
                  nsISupports *metadata)
      : mRoot(nullptr), mTail(nullptr), mRealm(nullptr) {
    DebugOnly<nsresult> rv =
        Set(path, realm, creds, challenge, ident, metadata);
    MOZ_ASSERT(NS_SUCCEEDED(rv));
  }
  ~nsHttpAuthEntry();

  MOZ_MUST_USE nsresult Set(const char *path, const char *realm,
                            const char *creds, const char *challenge,
                            const nsHttpAuthIdentity *ident,
                            nsISupports *metadata);

  nsHttpAuthIdentity mIdent;

  nsHttpAuthPath *mRoot;  // root pointer
  nsHttpAuthPath *mTail;  // tail pointer

  // allocated together in one blob, starting with mRealm.
  char *mRealm;
  char *mCreds;
  char *mChallenge;

  friend class nsHttpAuthNode;
  friend class nsHttpAuthCache;
  friend class nsAutoPtr<nsHttpAuthEntry>;  // needs to call the destructor
};

//-----------------------------------------------------------------------------
// nsHttpAuthNode
//-----------------------------------------------------------------------------

class nsHttpAuthNode {
 private:
  nsHttpAuthNode();
  ~nsHttpAuthNode();

  // path can be null, in which case we'll search for an entry
  // with a null path.
  nsHttpAuthEntry *LookupEntryByPath(const char *path);

  // realm must not be null
  nsHttpAuthEntry *LookupEntryByRealm(const char *realm);

  // if a matching entry is found, then credentials will be changed.
  MOZ_MUST_USE nsresult SetAuthEntry(const char *path, const char *realm,
                                     const char *credentials,
                                     const char *challenge,
                                     const nsHttpAuthIdentity *ident,
                                     nsISupports *metadata);

  void ClearAuthEntry(const char *realm);

  uint32_t EntryCount() { return mList.Length(); }

 private:
  nsTArray<nsAutoPtr<nsHttpAuthEntry> > mList;

  friend class nsHttpAuthCache;
  friend class nsAutoPtr<nsHttpAuthNode>;  // needs to call the destructor
};

//-----------------------------------------------------------------------------
// nsHttpAuthCache
//  (holds a hash table from host:port to nsHttpAuthNode)
//-----------------------------------------------------------------------------

class nsHttpAuthCache {
 public:
  nsHttpAuthCache();
  ~nsHttpAuthCache();

  // |scheme|, |host|, and |port| are required
  // |path| can be null
  // |entry| is either null or a weak reference
  MOZ_MUST_USE nsresult GetAuthEntryForPath(const char *scheme,
                                            const char *host, int32_t port,
                                            const char *path,
                                            nsACString const &originSuffix,
                                            nsHttpAuthEntry **entry);

  // |scheme|, |host|, and |port| are required
  // |realm| must not be null
  // |entry| is either null or a weak reference
  MOZ_MUST_USE nsresult GetAuthEntryForDomain(const char *scheme,
                                              const char *host, int32_t port,
                                              const char *realm,
                                              nsACString const &originSuffix,
                                              nsHttpAuthEntry **entry);

  // |scheme|, |host|, and |port| are required
  // |path| can be null
  // |realm| must not be null
  // if |credentials|, |user|, |pass|, and |challenge| are each
  // null, then the entry is deleted.
  MOZ_MUST_USE nsresult SetAuthEntry(const char *scheme, const char *host,
                                     int32_t port, const char *directory,
                                     const char *realm, const char *credentials,
                                     const char *challenge,
                                     nsACString const &originSuffix,
                                     const nsHttpAuthIdentity *ident,
                                     nsISupports *metadata);

  void ClearAuthEntry(const char *scheme, const char *host, int32_t port,
                      const char *realm, nsACString const &originSuffix);

  // expire all existing auth list entries including proxy auths.
  MOZ_MUST_USE nsresult ClearAll();

 private:
  nsHttpAuthNode *LookupAuthNode(const char *scheme, const char *host,
                                 int32_t port, nsACString const &originSuffix,
                                 nsCString &key);

  class OriginClearObserver : public nsIObserver {
    virtual ~OriginClearObserver() {}

   public:
    NS_DECL_ISUPPORTS
    NS_DECL_NSIOBSERVER
    explicit OriginClearObserver(nsHttpAuthCache *aOwner) : mOwner(aOwner) {}
    nsHttpAuthCache *mOwner;
  };

  void ClearOriginData(OriginAttributesPattern const &pattern);

 private:
  using AuthNodeTable = nsClassHashtable<nsCStringHashKey, nsHttpAuthNode>;
  AuthNodeTable mDB;  // "host:port" --> nsHttpAuthNode
  RefPtr<OriginClearObserver> mObserver;
};

}  // namespace net
}  // namespace mozilla

#endif  // nsHttpAuthCache_h__