Make handling of Http Authentication thread safe
* Each BHttpAuthentication object is locked on all field accesses, * They are owned by the BUrlContext and never deleted, so there is no need for reference-counting them, * The BUrlContext itself is now reference counted, and all BUrlRequests hold a reference to it. This makes sure using the BHttpAuthentication objects from requests is thread-safe.
This commit is contained in:
@@ -1,13 +1,14 @@
|
||||
/*
|
||||
* Copyright 2010 Haiku Inc. All rights reserved.
|
||||
* Copyright 2010-2014 Haiku Inc. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef _B_HTTP_AUTHENTICATION_H_
|
||||
#define _B_HTTP_AUTHENTICATION_H_
|
||||
|
||||
|
||||
#include <Url.h>
|
||||
#include <Locker.h>
|
||||
#include <String.h>
|
||||
#include <Url.h>
|
||||
|
||||
// HTTP authentication method
|
||||
enum BHttpAuthenticationMethod {
|
||||
@@ -89,6 +90,8 @@ private:
|
||||
BHttpAuthenticationQop fDigestQop;
|
||||
|
||||
BString fAuthorizationString;
|
||||
|
||||
mutable BLocker fLock;
|
||||
};
|
||||
|
||||
#endif // _B_HTTP_AUTHENTICATION_H_
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010 Haiku Inc. All rights reserved.
|
||||
* Copyright 2010-2014 Haiku Inc. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef _B_URL_CONTEXT_H_
|
||||
@@ -8,15 +8,16 @@
|
||||
|
||||
#include <HttpAuthentication.h>
|
||||
#include <NetworkCookieJar.h>
|
||||
#include <Referenceable.h>
|
||||
|
||||
|
||||
namespace BPrivate {
|
||||
template <class key, class value> class HashMap;
|
||||
template <class key, class value> class SynchronizedHashMap;
|
||||
class HashString;
|
||||
}
|
||||
|
||||
|
||||
class BUrlContext {
|
||||
class BUrlContext: public BReferenceable {
|
||||
public:
|
||||
BUrlContext();
|
||||
~BUrlContext();
|
||||
@@ -25,7 +26,7 @@ public:
|
||||
void SetCookieJar(
|
||||
const BNetworkCookieJar& cookieJar);
|
||||
void AddAuthentication(const BUrl& url,
|
||||
BHttpAuthentication* const authentication);
|
||||
const BHttpAuthentication& authentication);
|
||||
|
||||
// Context accessors
|
||||
BNetworkCookieJar& GetCookieJar();
|
||||
@@ -33,7 +34,7 @@ public:
|
||||
|
||||
private:
|
||||
BNetworkCookieJar fCookieJar;
|
||||
typedef BPrivate::HashMap<BPrivate::HashString,
|
||||
typedef BPrivate::SynchronizedHashMap<BPrivate::HashString,
|
||||
BHttpAuthentication*> BHttpAuthenticationMap;
|
||||
BHttpAuthenticationMap* fAuthenticationMap;
|
||||
};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010 Haiku Inc. All rights reserved.
|
||||
* Copyright 2010-2014 Haiku Inc. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef _B_URL_REQUEST_H_
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <UrlProtocolListener.h>
|
||||
#include <UrlResult.h>
|
||||
#include <OS.h>
|
||||
#include <Referenceable.h>
|
||||
|
||||
|
||||
class BUrlRequest {
|
||||
@@ -52,7 +53,7 @@ protected:
|
||||
const char* format, ...);
|
||||
protected:
|
||||
BUrl fUrl;
|
||||
BUrlContext* fContext;
|
||||
BReference<BUrlContext> fContext;
|
||||
BUrlProtocolListener* fListener;
|
||||
|
||||
bool fQuit;
|
||||
|
||||
@@ -9,9 +9,12 @@
|
||||
|
||||
#include <HttpAuthentication.h>
|
||||
|
||||
#include <cstdlib>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <AutoLocker.h>
|
||||
|
||||
|
||||
#include <cstdio>
|
||||
#if DEBUG > 0
|
||||
#define PRINT(x) printf x
|
||||
#else
|
||||
@@ -56,27 +59,35 @@ BHttpAuthentication::BHttpAuthentication(const BString& username, const BString&
|
||||
void
|
||||
BHttpAuthentication::SetUserName(const BString& username)
|
||||
{
|
||||
fLock.Lock();
|
||||
fUserName = username;
|
||||
fLock.Unlock();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
BHttpAuthentication::SetPassword(const BString& password)
|
||||
{
|
||||
fLock.Lock();
|
||||
fPassword = password;
|
||||
fLock.Unlock();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
BHttpAuthentication::SetMethod(BHttpAuthenticationMethod method)
|
||||
{
|
||||
fLock.Lock();
|
||||
fAuthenticationMethod = method;
|
||||
fLock.Unlock();
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
BHttpAuthentication::Initialize(const BString& wwwAuthenticate)
|
||||
{
|
||||
BPrivate::AutoLocker<BLocker> lock(fLock);
|
||||
|
||||
fAuthenticationMethod = B_HTTP_AUTHENTICATION_NONE;
|
||||
fDigestQop = B_HTTP_QOP_NONE;
|
||||
|
||||
@@ -171,6 +182,7 @@ BHttpAuthentication::Initialize(const BString& wwwAuthenticate)
|
||||
const BString&
|
||||
BHttpAuthentication::UserName() const
|
||||
{
|
||||
BPrivate::AutoLocker<BLocker> lock(fLock);
|
||||
return fUserName;
|
||||
}
|
||||
|
||||
@@ -178,6 +190,7 @@ BHttpAuthentication::UserName() const
|
||||
const BString&
|
||||
BHttpAuthentication::Password() const
|
||||
{
|
||||
BPrivate::AutoLocker<BLocker> lock(fLock);
|
||||
return fPassword;
|
||||
}
|
||||
|
||||
@@ -185,6 +198,7 @@ BHttpAuthentication::Password() const
|
||||
BHttpAuthenticationMethod
|
||||
BHttpAuthentication::Method() const
|
||||
{
|
||||
BPrivate::AutoLocker<BLocker> lock(fLock);
|
||||
return fAuthenticationMethod;
|
||||
}
|
||||
|
||||
@@ -192,6 +206,7 @@ BHttpAuthentication::Method() const
|
||||
BString
|
||||
BHttpAuthentication::Authorization(const BUrl& url, const BString& method) const
|
||||
{
|
||||
BPrivate::AutoLocker<BLocker> lock(fLock);
|
||||
BString authorizationString;
|
||||
|
||||
switch (fAuthenticationMethod) {
|
||||
|
||||
@@ -378,15 +378,14 @@ BHttpRequest::_ProtocolLoop()
|
||||
if (authentication->Method() == B_HTTP_AUTHENTICATION_NONE) {
|
||||
// There is no authentication context for this
|
||||
// url yet, so let's create one.
|
||||
authentication
|
||||
= new(std::nothrow) BHttpAuthentication();
|
||||
if (authentication == NULL)
|
||||
status = B_NO_MEMORY;
|
||||
else {
|
||||
status = authentication->Initialize(
|
||||
fHeaders["WWW-Authenticate"]);
|
||||
fContext->AddAuthentication(fUrl, authentication);
|
||||
}
|
||||
BHttpAuthentication newAuth;
|
||||
newAuth.Initialize(fHeaders["WWW-Authenticate"]);
|
||||
fContext->AddAuthentication(fUrl, newAuth);
|
||||
|
||||
// Get the copy of the authentication we just added.
|
||||
// That copy is owned by the BUrlContext and won't be
|
||||
// deleted (unlike the temporary object above)
|
||||
authentication = &fContext->GetAuthentication(fUrl);
|
||||
}
|
||||
|
||||
newRequest = false;
|
||||
|
||||
@@ -52,21 +52,25 @@ BUrlContext::SetCookieJar(const BNetworkCookieJar& cookieJar)
|
||||
|
||||
void
|
||||
BUrlContext::AddAuthentication(const BUrl& url,
|
||||
BHttpAuthentication* const authentication)
|
||||
const BHttpAuthentication& authentication)
|
||||
{
|
||||
BString domain = url.Host();
|
||||
domain += url.Path();
|
||||
BPrivate::HashString hostHash(domain.String(), domain.Length());
|
||||
|
||||
fAuthenticationMap->Lock();
|
||||
|
||||
BHttpAuthentication* previous = fAuthenticationMap->Get(hostHash);
|
||||
|
||||
// Make sure we don't leak memory by overriding a previous
|
||||
// authentication for the same domain.
|
||||
if (authentication != previous) {
|
||||
fAuthenticationMap->Put(hostHash, authentication);
|
||||
// replaces the old one, or adds it in case previous == NULL
|
||||
delete previous;
|
||||
if (previous)
|
||||
*previous = authentication;
|
||||
else {
|
||||
BHttpAuthentication* copy
|
||||
= new(std::nothrow) BHttpAuthentication(authentication);
|
||||
fAuthenticationMap->Put(hostHash, copy);
|
||||
}
|
||||
|
||||
fAuthenticationMap->Unlock();
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user