Compare commits

...

3 Commits

Author SHA1 Message Date
Leorize bfa6894640 Preliminary work on the switch to BUrlSession
This is a basic adaption of the current WebKit to make use of
BUrlSession. It's done enough for HaikuLauncher to compile, however I've
not managed to throughly test it due as my VM died.
2021-01-28 20:45:49 +01:00
Leorize b07f99d2ef Preliminary support for output-to-BDataIO 2021-01-28 20:45:48 +01:00
Leorize fb627e96a5 platform/network/haiku: rework networking backend
Main changes in this commit:
- BUrlProtocolHandler is splitted into two classes:
  - BUrlProtocolHandler for managing the request lifetime.
  - BUrlRequestWrapper for handling events from requests spawned by
    BUrlProtocolHandler.

  The separation allow the events handling code to be greatly
  simplified, and code for handling events and managing request
  are now properly separated.

  In the future this enables BUrlProtocolHandler to be the
  synchronization/serialization point, allowing BUrlRequestWrapper to
  interface with BUrlRequest directly instead of going through
  BUrlProtocolAsynchronousRequest, which should allow for better
  performance.

- Redirection and authentication are now handled manually by the backend
  instead of delegating to BUrlRequest.

- Code style has been adjusted to match WebKit official style guideline.
2021-01-28 20:45:47 +01:00
22 changed files with 732 additions and 585 deletions

View File

@ -42,7 +42,7 @@
#if PLATFORM(COCOA) || USE(CFURLCONNECTION)
#include <wtf/RetainPtr.h>
#elif PLATFORM(HAIKU)
class BUrlContext;
class BUrlSession;
#endif
#if PLATFORM(COCOA)
@ -144,8 +144,8 @@ public:
WEBCORE_EXPORT NetworkStorageSession(PAL::SessionID);
~NetworkStorageSession();
BUrlContext& platformSession() const;
void setPlatformSession(BUrlContext*);
BUrlSession& platformSession() const;
void setPlatformSession(BUrlSession*);
#elif USE(CURL)
WEBCORE_EXPORT NetworkStorageSession(PAL::SessionID);
~NetworkStorageSession();
@ -265,7 +265,7 @@ private:
GRefPtr<SoupCookieJar> m_cookieStorage;
Function<void ()> m_cookieObserverHandler;
#elif USE(HAIKU)
BUrlContext* m_context;
BUrlSession* m_context;
#elif USE(CURL)
mutable UniqueRef<CookieJarDB> m_cookieDatabase;
#else

View File

@ -20,7 +20,7 @@
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
@ -82,7 +82,7 @@ public:
, m_currentRequest(request)
#endif
#if PLATFORM(HAIKU)
, m_urlrequest(0)
, m_urlrequest(0)
#endif
, m_failureTimer(*loader, &ResourceHandle::failureTimerFired)
{
@ -91,7 +91,7 @@ public:
m_password = url.password();
m_firstRequest.removeCredentials();
}
~ResourceHandleInternal();
ResourceHandleClient* client() { return m_client; }
@ -105,9 +105,9 @@ public:
// Suggested credentials for the current redirection step.
String m_user;
String m_password;
Credential m_initialCredential;
int status { 0 };
bool m_defersLoading;
@ -130,7 +130,7 @@ public:
#endif
#if USE(CURL)
std::unique_ptr<CurlResourceHandleDelegate> m_delegate;
bool m_cancelled { false };
unsigned m_redirectCount { 0 };
unsigned m_authFailureCount { 0 };
@ -141,8 +141,8 @@ public:
#endif
#if PLATFORM(HAIKU)
BUrlProtocolHandler* m_urlrequest;
BString m_url;
BUrlProtocolHandler* m_urlrequest;
BString m_url;
#endif
#if PLATFORM(COCOA)

View File

@ -31,6 +31,7 @@
#include "ResourceHandleInternal.h"
#include "ResourceResponse.h"
#include "ResourceRequest.h"
#include "SharedBuffer.h"
#include <wtf/CompletionHandler.h>
#include <wtf/text/CString.h>
@ -46,108 +47,194 @@ static const int gMaxRecursionLimit = 10;
namespace WebCore {
BUrlProtocolHandler::BUrlProtocolHandler(NetworkingContext* context,
ResourceHandle* handle, bool synchronous)
: BUrlProtocolAsynchronousListener(!synchronous)
, m_resourceHandle(handle)
, m_redirected(false)
, m_responseDataSent(false)
, m_postData(NULL)
, m_request(handle->firstRequest().toNetworkRequest(
context ? &context->storageSession()->platformSession() : nullptr))
, m_position(0)
, m_redirectionTries(gMaxRecursionLimit)
static bool shouldRedirectAsGET(const ResourceRequest& request, int statusCode, bool crossOrigin)
{
if (!m_resourceHandle)
return;
BString method = BString(m_resourceHandle->firstRequest().httpMethod());
m_postData = NULL;
if (m_request == NULL)
return;
m_baseUrl = URL(m_request->Url());
BHttpRequest* httpRequest = dynamic_cast<BHttpRequest*>(m_request);
if(httpRequest) {
// TODO maybe we have data to send in other cases ?
if(method == B_HTTP_POST || method == B_HTTP_PUT) {
FormData* form = m_resourceHandle->firstRequest().httpBody();
if(form) {
m_postData = new BFormDataIO(form, context->storageSession()->sessionID());
httpRequest->AdoptInputData(m_postData, m_postData->Size());
}
}
httpRequest->SetMethod(method.String());
}
// In synchronous mode, call this listener directly.
// In asynchronous mode, go through a BMessage
if(this->SynchronousListener()) {
m_request->SetListener(this->SynchronousListener());
} else {
m_request->SetListener(this);
}
if (m_request->Run() < B_OK) {
ResourceHandleClient* client = m_resourceHandle->client();
if (!client)
return;
ResourceError error("BUrlProtocol", 42,
handle->firstRequest().url(),
"The service kit failed to start the request.");
client->didFail(m_resourceHandle, error);
}
}
BUrlProtocolHandler::~BUrlProtocolHandler()
{
abort();
if (m_request)
m_request->SetListener(NULL);
delete m_request;
}
void BUrlProtocolHandler::abort()
{
if (m_resourceHandle != NULL && m_request != NULL)
m_request->Stop();
m_resourceHandle = NULL;
}
static bool ignoreHttpError(BHttpRequest* reply, bool receivedData)
{
int httpStatusCode = static_cast<const BHttpResult&>(reply->Result()).StatusCode();
if (httpStatusCode == 401 || httpStatusCode == 407)
if (request.httpMethod() == "GET" || request.httpMethod() == "HEAD")
return false;
if (receivedData && (httpStatusCode >= 400 && httpStatusCode < 600))
if (statusCode == 303)
return true;
if ((statusCode == 301 || statusCode == 302) && request.httpMethod() == "POST")
return true;
if (crossOrigin && request.httpMethod() == "DELETE")
return true;
return false;
}
void BUrlProtocolHandler::RequestCompleted(BUrlRequest* caller, bool success)
RefPtr<BUrlRequestWrapper> BUrlRequestWrapper::create(BUrlProtocolHandler* handler, NetworkStorageSession* storageSession, ResourceRequest& request)
{
if (!m_resourceHandle)
return adoptRef(*new BUrlRequestWrapper(handler, storageSession, request));
}
BUrlRequestWrapper::BUrlRequestWrapper(BUrlProtocolHandler* handler, NetworkStorageSession* storageSession, ResourceRequest& request)
: BUrlProtocolAsynchronousListener(true)
, m_handler(handler)
, m_receiveMutex()
{
ASSERT(isMainThread());
ASSERT(m_handler);
ASSERT(storageSession);
m_request = request.toNetworkRequest(&storageSession->platformSession());
if (!m_request)
return;
ResourceHandleClient* client = m_resourceHandle->client();
if (!client)
m_request->SetListener(SynchronousListener());
m_request->SetOutput(this);
BHttpRequest* httpRequest = dynamic_cast<BHttpRequest*>(m_request);
if (httpRequest) {
if (request.httpMethod() == "POST" || request.httpMethod() == "PUT") {
if (request.httpBody()) {
auto postData = new BFormDataIO(request.httpBody(), storageSession->sessionID());
httpRequest->AdoptInputData(postData, postData->Size());
}
}
httpRequest->SetMethod(request.httpMethod().utf8().data());
// Redirections will be handled by this class.
httpRequest->SetFollowLocation(false);
} else if (request.httpMethod() != "GET") {
// Only the HTTP backend support things other than GET.
// Remove m_request to signify to ResourceHandle that the request was
// invalid.
delete m_request;
m_request = NULL;
return;
}
// Keep self alive while BUrlRequest is running as we hold
// the main dispatcher.
ref();
// Block the receiving thread until headers are parsed.
m_receiveMutex.lock();
if (m_request->Run() < B_OK) {
deref();
ResourceError error("BUrlProtocol", 42,
request.url(),
"The service kit failed to start the request.");
m_handler->didFail(error);
return;
}
}
BUrlRequestWrapper::~BUrlRequestWrapper()
{
abort();
delete m_request;
}
void BUrlRequestWrapper::abort()
{
ASSERT(isMainThread());
{
// Lock if we have already unblocked the receive thread to
// synchronize cancellation status.
auto locker = holdLockIf(m_receiveMutex, m_didUnblockReceive);
m_handler = nullptr;
}
// If the receive thread is still blocked, unblock it so that it
// become aware of the state change.
if (!m_didUnblockReceive) {
m_didUnblockReceive = true;
m_receiveMutex.unlock();
}
if (m_request)
m_request->Stop();
}
void BUrlRequestWrapper::HeadersReceived(BUrlRequest* caller)
{
ASSERT(isMainThread());
if (!m_handler)
return;
const BUrlResult& result = caller->Result();
ResourceResponse response(URL(caller->Url()),
extractMIMETypeFromMediaType(result.ContentType()), result.Length(),
extractCharsetFromMediaType(result.ContentType()));
const BHttpResult* httpResult = dynamic_cast<const BHttpResult*>(&result);
if (httpResult) {
String suggestedFilename = filenameFromHTTPContentDisposition(
httpResult->Headers()["Content-Disposition"]);
if (!suggestedFilename.isEmpty())
response.setSuggestedFilename(suggestedFilename);
response.setHTTPStatusCode(httpResult->StatusCode());
response.setHTTPStatusText(httpResult->StatusText());
// Add remaining headers.
const BHttpHeaders& resultHeaders = httpResult->Headers();
for (int i = 0; i < resultHeaders.CountHeaders(); i++) {
BHttpHeader& headerPair = resultHeaders.HeaderAt(i);
response.setHTTPHeaderField(headerPair.Name(), headerPair.Value());
}
if (response.isRedirection() && !response.httpHeaderField(HTTPHeaderName::Location).isEmpty()) {
m_handler->willSendRequest(response);
return;
}
if (response.httpStatusCode() == 401 && m_handler->didReceiveAuthenticationChallenge(response))
return;
}
ResourceResponse responseCopy = response;
m_handler->didReceiveResponse(WTFMove(responseCopy));
// Unblock receive thread
if (!m_didUnblockReceive) {
m_didUnblockReceive = true;
m_receiveMutex.unlock();
}
}
void BUrlRequestWrapper::UploadProgress(BUrlRequest*, ssize_t bytesSent, ssize_t bytesTotal)
{
ASSERT(isMainThread());
if (!m_handler)
return;
m_handler->didSendData(bytesSent, bytesTotal);
}
void BUrlRequestWrapper::RequestCompleted(BUrlRequest* caller, bool success)
{
ASSERT(isMainThread());
// We held a pointer to keep the main dispatcher alive for the duration
// of the request run.
//
// As the request completes, we adopt the ref here so that it can
// release itself after completion.
auto releaseThis = adoptRef(*this);
if (!m_handler)
return;
BHttpRequest* httpRequest = dynamic_cast<BHttpRequest*>(m_request);
if (success || (httpRequest && ignoreHttpError(httpRequest, m_responseDataSent))) {
client->didFinishLoading(m_resourceHandle);
if (success || (httpRequest && m_didReceiveData)) {
m_handler->didFinishLoading();
return;
} else if(httpRequest) {
} else if (httpRequest) {
const BHttpResult& result = static_cast<const BHttpResult&>(httpRequest->Result());
int httpStatusCode = result.StatusCode();
@ -155,7 +242,7 @@ void BUrlProtocolHandler::RequestCompleted(BUrlRequest* caller, bool success)
ResourceError error("HTTP", httpStatusCode,
URL(caller->Url()), strerror(caller->Status()));
client->didFail(m_resourceHandle, error);
m_handler->didFail(error);
return;
}
}
@ -163,35 +250,154 @@ void BUrlProtocolHandler::RequestCompleted(BUrlRequest* caller, bool success)
// If we get here, it means we are in failure without an HTTP error code
// (DNS error, or error from a protocol other than HTTP).
ResourceError error("BUrlRequest", caller->Status(), URL(caller->Url()), strerror(caller->Status()));
client->didFail(m_resourceHandle, error);
m_handler->didFail(error);
}
bool BUrlProtocolHandler::CertificateVerificationFailed(BUrlRequest*,
bool BUrlRequestWrapper::CertificateVerificationFailed(BUrlRequest*,
BCertificate& certificate, const char* message)
{
return m_resourceHandle->didReceiveInvalidCertificate(certificate, message);
ASSERT(isMainThread());
if (!m_handler)
return false;
return m_handler->didReceiveInvalidCertificate(certificate, message);
}
ssize_t BUrlRequestWrapper::Write(const void* data, size_t size)
{
auto locker = holdLock(m_receiveMutex);
void BUrlProtocolHandler::AuthenticationNeeded(BHttpRequest* request, ResourceResponse& response)
if (!m_handler)
return size;
if (size > 0) {
m_didReceiveData = true;
auto buffer = SharedBuffer::create(reinterpret_cast<const char*>(data), size);
callOnMainThread([this, protectedThis = makeRef(*this), buffer = WTFMove(buffer)]() mutable {
if (m_handler)
m_handler->didReceiveBuffer(WTFMove(buffer));
});
}
return size;
}
BUrlProtocolHandler::BUrlProtocolHandler(ResourceHandle* handle)
: m_resourceHandle(handle)
, m_request()
{
if (!m_resourceHandle)
return;
ResourceHandleInternal* d = m_resourceHandle->getInternal();
unsigned failureCount = 0;
m_resourceRequest = m_resourceHandle->firstRequest();
m_request = BUrlRequestWrapper::create(this,
m_resourceHandle->context()->storageSession(),
m_resourceRequest);
}
const URL& url = m_resourceHandle->firstRequest().url();
BUrlProtocolHandler::~BUrlProtocolHandler()
{
abort();
}
void BUrlProtocolHandler::abort()
{
ASSERT(isMainThread());
if (m_request)
m_request->abort();
m_resourceHandle = nullptr;
}
void BUrlProtocolHandler::didFail(const ResourceError& error)
{
ASSERT(isMainThread());
ResourceHandleClient* client = m_resourceHandle->client();
if (!client)
return;
client->didFail(m_resourceHandle, error);
}
void BUrlProtocolHandler::willSendRequest(const ResourceResponse& response)
{
ASSERT(isMainThread());
if (!m_resourceHandle)
return;
ResourceHandleClient* client = m_resourceHandle->client();
if (!client)
return;
ResourceRequest request = m_resourceHandle->firstRequest();
m_redirectionTries++;
if (m_redirectionTries > gMaxRecursionLimit) {
ResourceError error(request.url().host().utf8().data(), 400, request.url(),
"Redirection limit reached");
client->didFail(m_resourceHandle, error);
return;
}
URL newUrl = URL(request.url(), response.httpHeaderField(HTTPHeaderName::Location));
bool crossOrigin = !protocolHostAndPortAreEqual(request.url(), newUrl);
request.setURL(newUrl);
if (!newUrl.protocolIsInHTTPFamily() || shouldRedirectAsGET(request, response.httpStatusCode(), crossOrigin)) {
request.setHTTPMethod("GET");
request.setHTTPBody(nullptr);
request.clearHTTPContentType();
}
if (crossOrigin) {
request.clearHTTPAuthorization();
request.clearHTTPOrigin();
}
m_request->abort();
ResourceResponse responseCopy = response;
client->willSendRequestAsync(m_resourceHandle, WTFMove(request), WTFMove(responseCopy), [this] (ResourceRequest&& request) {
continueAfterWillSendRequest(WTFMove(request));
});
}
void BUrlProtocolHandler::continueAfterWillSendRequest(ResourceRequest&& request)
{
ASSERT(isMainThread());
// willSendRequestAsync might cancel the request
if (!m_resourceHandle->client() || request.isNull())
return;
m_resourceRequest = request;
m_request = BUrlRequestWrapper::create(this, m_resourceHandle->context()->storageSession(), request);
}
bool BUrlProtocolHandler::didReceiveAuthenticationChallenge(const ResourceResponse& response)
{
ASSERT(isMainThread());
if (!m_resourceHandle || !m_resourceHandle->client())
return false;
const URL& url = response.url();
ProtectionSpaceServerType serverType = ProtectionSpaceServerHTTP;
if (url.protocolIs("https"))
serverType = ProtectionSpaceServerHTTPS;
String challenge = static_cast<const BHttpResult&>(request->Result()).Headers()["WWW-Authenticate"];
static NeverDestroyed<String> wwwAuthenticate(MAKE_STATIC_STRING_IMPL("www-authenticate"));
String challenge = response.httpHeaderField(wwwAuthenticate);
ProtectionSpaceAuthenticationScheme scheme = ProtectionSpaceAuthenticationSchemeDefault;
ResourceHandleClient* client = m_resourceHandle->client();
// TODO according to RFC7235, there could be more than one challenge in WWW-Authenticate. We
// should parse them all, instead of just the first one.
if (challenge.startsWith("Digest"))
@ -201,7 +407,7 @@ void BUrlProtocolHandler::AuthenticationNeeded(BHttpRequest* request, ResourceRe
else {
// Unknown authentication type, ignore (various websites are intercepting the auth and
// handling it by themselves)
return;
return false;
}
String realm;
@ -223,177 +429,85 @@ void BUrlProtocolHandler::AuthenticationNeeded(BHttpRequest* request, ResourceRe
ProtectionSpace protectionSpace(url.host().utf8().data(), port, serverType, realm, scheme);
ResourceError resourceError(url.host().utf8().data(), 401, url, String());
m_redirectionTries--;
if(m_redirectionTries == 0)
{
client->didFinishLoading(m_resourceHandle);
return;
}
ResourceHandleInternal* d = m_resourceHandle->getInternal();
Credential proposedCredential(d->m_user, d->m_password, CredentialPersistenceForSession);
AuthenticationChallenge authenticationChallenge(protectionSpace,
proposedCredential, failureCount++, response, resourceError);
proposedCredential, m_authenticationTries++, response, resourceError);
authenticationChallenge.m_authenticationClient = m_resourceHandle;
m_resourceHandle->didReceiveAuthenticationChallenge(authenticationChallenge);
// will set m_user and m_password in ResourceHandleInternal
// will set m_user and m_password in ResourceHandleInternal
if (d->m_user != "") {
// Handle this just like redirects.
m_redirected = true;
ResourceRequest request = m_resourceHandle->firstRequest();
ResourceResponse responseCopy = response;
ResourceRequest request = m_resourceRequest;
ResourceResponse responseCopy = response;
request.setCredentials(d->m_user.utf8().data(), d->m_password.utf8().data());
client->willSendRequestAsync(m_resourceHandle, WTFMove(request), WTFMove(responseCopy),
[handle = makeRef(*m_resourceHandle)] (ResourceRequest&& request) {
//continueAfterWillSendRequest(handle.ptr(), WTFMove(request));
});
} else {
// Anything to do in case of failure?
}
}
void BUrlProtocolHandler::ConnectionOpened(BUrlRequest*)
{
m_responseDataSent = false;
}
void BUrlProtocolHandler::HeadersReceived(BUrlRequest* caller,
const BUrlResult& result)
{
if (!m_resourceHandle)
return;
const BHttpResult* httpResult = dynamic_cast<const BHttpResult*>(&result);
WTF::String contentType = result.ContentType();
int contentLength = result.Length();
URL url;
WTF::String encoding = extractCharsetFromMediaType(contentType);
WTF::String mimeType = extractMIMETypeFromMediaType(contentType);
if (httpResult) {
url = URL(httpResult->Url());
BString location = httpResult->Headers()["Location"];
if (location.Length() > 0) {
m_redirected = true;
url = URL(url, location);
} else {
m_redirected = false;
}
} else {
url = m_baseUrl;
}
ResourceResponse response(url, mimeType, contentLength, encoding);
if (httpResult) {
int statusCode = httpResult->StatusCode();
String suggestedFilename = filenameFromHTTPContentDisposition(
httpResult->Headers()["Content-Disposition"]);
if (!suggestedFilename.isEmpty())
response.setSuggestedFilename(suggestedFilename);
response.setHTTPStatusCode(statusCode);
response.setHTTPStatusText(httpResult->StatusText());
// Add remaining headers.
const BHttpHeaders& resultHeaders = httpResult->Headers();
for (int i = 0; i < resultHeaders.CountHeaders(); i++) {
BHttpHeader& headerPair = resultHeaders.HeaderAt(i);
response.setHTTPHeaderField(headerPair.Name(), headerPair.Value());
}
if (statusCode == 401) {
AuthenticationNeeded((BHttpRequest*)m_request, response);
// AuthenticationNeeded may have aborted the request
// so we need to make sure we can continue.
if (!m_resourceHandle)
return;
}
}
ResourceHandleClient* client = m_resourceHandle->client();
if (!client)
return;
if (m_redirected) {
m_redirectionTries--;
if (m_redirectionTries == 0) {
ResourceError error(url.host().utf8().data(), 400, url,
"Redirection limit reached");
client->didFail(m_resourceHandle, error);
return;
}
// Notify the client that we are redirecting.
ResourceRequest request = m_resourceHandle->firstRequest();
ResourceResponse responseCopy = response;
request.setURL(url);
client->willSendRequestAsync(m_resourceHandle, WTFMove(request), WTFMove(responseCopy),
[handle = makeRef(*m_resourceHandle)] (ResourceRequest&& request) {
//continueAfterWillSendRequest(handle.ptr(), WTFMove(request));
});
} else {
ResourceResponse responseCopy = response;
// Make sure the resource handle is not deleted immediately, otherwise
// didReceiveResponse would crash. Keep a reference to it so it can be
// deleted cleanly after the function returns.
RefPtr<ResourceHandle> protectedHandle(m_resourceHandle);
protectedHandle->didReceiveResponse(WTFMove(responseCopy), [this/*, protectedThis = makeRef(*this)*/] {
//continueAfterDidReceiveResponse();
m_request->abort();
m_resourceHandle->client()->willSendRequestAsync(m_resourceHandle,
WTFMove(request), WTFMove(responseCopy), [this] (ResourceRequest&& request) {
continueAfterWillSendRequest(WTFMove(request));
});
return true;
}
return false;
}
void BUrlProtocolHandler::DataReceived(BUrlRequest* caller, const char* data,
off_t position, ssize_t size)
void BUrlProtocolHandler::didReceiveResponse(ResourceResponse&& response)
{
ASSERT(isMainThread());
if (!m_resourceHandle)
return;
ResourceHandleClient* client = m_resourceHandle->client();
if (!client)
return;
// don't emit the "Document has moved here" type of HTML
if (m_redirected)
return;
if (position != m_position)
{
debugger("bad redirect");
return;
}
if (size > 0) {
m_responseDataSent = true;
client->didReceiveData(m_resourceHandle, data, size, size);
}
m_position += size;
// Make sure the resource handle is not deleted immediately, otherwise
// didReceiveResponse would crash. Keep a reference to it so it can be
// deleted cleanly after the function returns.
auto protectedHandle = makeRef(*m_resourceHandle);
protectedHandle->didReceiveResponse(WTFMove(response), [this/*, protectedThis = makeRef(*this)*/] {
//continueAfterDidReceiveResponse();
});
}
void BUrlProtocolHandler::UploadProgress(BUrlRequest* caller, ssize_t bytesSent, ssize_t bytesTotal)
void BUrlProtocolHandler::didReceiveBuffer(Ref<SharedBuffer>&& buffer)
{
ASSERT(isMainThread());
if (!m_resourceHandle || !m_resourceHandle->client())
return;
m_resourceHandle->client()->didReceiveBuffer(m_resourceHandle, WTFMove(buffer), buffer->size());
}
void BUrlProtocolHandler::didSendData(ssize_t bytesSent, ssize_t bytesTotal)
{
ASSERT(isMainThread());
if (!m_resourceHandle || !m_resourceHandle->client())
return;
m_resourceHandle->client()->didSendData(m_resourceHandle, bytesSent, bytesTotal);
}
void BUrlProtocolHandler::didFinishLoading()
{
ASSERT(isMainThread());
if (!m_resourceHandle || !m_resourceHandle->client())
return;
m_resourceHandle->client()->didFinishLoading(m_resourceHandle);
}
bool BUrlProtocolHandler::didReceiveInvalidCertificate(BCertificate& certificate, const char* message)
{
ASSERT(isMainThread());
if (!m_resourceHandle)
return;
return false;
ResourceHandleClient* client = m_resourceHandle->client();
if (!client)
return;
client->didSendData(m_resourceHandle, bytesSent, bytesTotal);
return m_resourceHandle->didReceiveInvalidCertificate(certificate, message);
}
}
} // namespace WebCore

View File

@ -21,6 +21,7 @@
#include "HaikuFormDataStream.h"
#include "ResourceRequest.h"
#include "ResourceError.h"
#include <support/Locker.h>
#include <Messenger.h>
@ -32,41 +33,76 @@ class BFile;
namespace WebCore {
class NetworkingContext;
class NetworkStorageSession;
class ResourceHandle;
class ResourceResponse;
class BUrlProtocolHandler : public BUrlProtocolAsynchronousListener
{
class BUrlProtocolHandler;
class BUrlRequestWrapper;
class BUrlRequestWrapper : public ThreadSafeRefCounted<BUrlRequestWrapper>, public BUrlProtocolAsynchronousListener, public BDataIO {
public:
BUrlProtocolHandler(NetworkingContext* context, ResourceHandle *handle,
bool synchronous);
virtual ~BUrlProtocolHandler();
static RefPtr<BUrlRequestWrapper> create(BUrlProtocolHandler*, NetworkStorageSession*, ResourceRequest&);
virtual ~BUrlRequestWrapper();
void abort();
bool isValid() { return m_request != NULL; }
bool isValid() const { return m_request; };
private:
void AuthenticationNeeded(BHttpRequest* caller, ResourceResponse& response);
// BUrlListener hooks
void ConnectionOpened(BUrlRequest* caller) override;
void HeadersReceived(BUrlRequest* caller, const BUrlResult& result) override;
void DataReceived(BUrlRequest* caller, const char* data, off_t position,
ssize_t size) override;
// BUrlProtocolListener hooks
void HeadersReceived(BUrlRequest* caller) override;
void UploadProgress(BUrlRequest* caller, ssize_t bytesSent, ssize_t bytesTotal) override;
void RequestCompleted(BUrlRequest* caller, bool success) override;
bool CertificateVerificationFailed(BUrlRequest* caller, BCertificate& certificate, const char* message) override;
bool CertificateVerificationFailed(BUrlRequest* caller, BCertificate&, const char* message) override;
// BDataIO
ssize_t Write(const void*, size_t) override;
private:
ResourceHandle* m_resourceHandle;
bool m_redirected;
bool m_responseDataSent;
BFormDataIO* m_postData;
BUrlRequest* m_request;
off_t m_position;
URL m_baseUrl;
BUrlRequestWrapper(BUrlProtocolHandler*, NetworkStorageSession*, ResourceRequest&);
int m_redirectionTries;
private:
BUrlProtocolHandler* m_handler { nullptr };
BUrlRequest* m_request { nullptr };
bool m_didReceiveData { false };
bool m_didUnblockReceive { false };
// This lock is in charge of two things:
// - Whether data can be received.
// - Synchronizing cancellation via m_handler.
Lock m_receiveMutex;
};
class BUrlProtocolHandler {
public:
explicit BUrlProtocolHandler(ResourceHandle *handle);
virtual ~BUrlProtocolHandler();
void abort();
bool isValid() const { return m_request && m_request->isValid(); }
private:
void didFail(const ResourceError& error);
void willSendRequest(const ResourceResponse& response);
void continueAfterWillSendRequest(ResourceRequest&& request);
bool didReceiveAuthenticationChallenge(const ResourceResponse& response);
void didReceiveResponse(ResourceResponse&& response);
void didReceiveBuffer(Ref<SharedBuffer>&&);
void didSendData(ssize_t bytesSent, ssize_t bytesTotal);
void didFinishLoading();
bool didReceiveInvalidCertificate(BCertificate&, const char* message);
private:
friend class BUrlRequestWrapper;
ResourceRequest m_resourceRequest;
ResourceHandle* m_resourceHandle;
RefPtr<BUrlRequestWrapper> m_request;
unsigned m_redirectionTries { 0 };
unsigned m_authenticationTries { 0 };
};
}

View File

@ -28,7 +28,7 @@
#include "NetworkStorageSession.h"
#include <support/Locker.h>
#include <UrlContext.h>
#include <UrlSession.h>
#include "Cookie.h"
#include "CookieRequestHeaderFieldProxy.h"
@ -63,19 +63,19 @@ static std::unique_ptr<NetworkStorageSession>& defaultSession()
}
void NetworkStorageSession::setCookiesFromDOM(const URL& firstParty,
const SameSiteInfo& sameSiteInfo, const URL& url,
WTF::Optional<FrameIdentifier> frameID, WTF::Optional<PageIdentifier> pageID,
ShouldAskITP, const String& value, ShouldRelaxThirdPartyCookieBlocking) const
const SameSiteInfo& sameSiteInfo, const URL& url,
WTF::Optional<FrameIdentifier> frameID, WTF::Optional<PageIdentifier> pageID,
ShouldAskITP, const String& value, ShouldRelaxThirdPartyCookieBlocking) const
{
BNetworkCookie* heapCookie
= new BNetworkCookie(value, BUrl(url));
BNetworkCookie* heapCookie
= new BNetworkCookie(value, BUrl(url));
#if TRACE_COOKIE_JAR
printf("CookieJar: Add %s for %s\n", heapCookie->RawCookie(true).String(),
printf("CookieJar: Add %s for %s\n", heapCookie->RawCookie(true).String(),
url.string().utf8().data());
printf(" from %s\n", value.utf8().data());
printf(" from %s\n", value.utf8().data());
#endif
platformSession().GetCookieJar().AddCookie(heapCookie);
platformSession().GetCookieJar().AddCookie(heapCookie);
}
HTTPCookieAcceptPolicy NetworkStorageSession::cookieAcceptPolicy() const
@ -84,39 +84,39 @@ HTTPCookieAcceptPolicy NetworkStorageSession::cookieAcceptPolicy() const
}
std::pair<String, bool> NetworkStorageSession::cookiesForDOM(const URL& firstParty,
const SameSiteInfo& sameSiteInfo, const URL& url,
WTF::Optional<FrameIdentifier> frameID, WTF::Optional<PageIdentifier> pageID,
IncludeSecureCookies includeSecureCookies, ShouldAskITP,
ShouldRelaxThirdPartyCookieBlocking) const
const SameSiteInfo& sameSiteInfo, const URL& url,
WTF::Optional<FrameIdentifier> frameID, WTF::Optional<PageIdentifier> pageID,
IncludeSecureCookies includeSecureCookies, ShouldAskITP,
ShouldRelaxThirdPartyCookieBlocking) const
{
#if TRACE_COOKIE_JAR
printf("CookieJar: Request for %s\n", url.string().utf8().data());
printf("CookieJar: Request for %s\n", url.string().utf8().data());
#endif
BString result;
BUrl hUrl(url);
bool secure = false;
BString result;
BUrl hUrl(url);
bool secure = false;
const BNetworkCookie* c;
for (BNetworkCookieJar::UrlIterator it(
const BNetworkCookie* c;
for (BNetworkCookieJar::UrlIterator it(
platformSession().GetCookieJar().GetUrlIterator(hUrl));
(c = it.Next()); ) {
(c = it.Next()); ) {
// filter out httpOnly cookies,as this method is used to get cookies
// from JS code and these shouldn't be visible there.
if(c->HttpOnly())
continue;
continue;
// filter out secure cookies if they should be
if (c->Secure())
{
secure = true;
// filter out secure cookies if they should be
if (c->Secure())
{
secure = true;
if (includeSecureCookies == IncludeSecureCookies::No)
continue;
}
result << "; " << c->RawCookie(false);
}
result.Remove(0, 2);
continue;
}
result << "; " << c->RawCookie(false);
}
result.Remove(0, 2);
return {result, secure};
}
@ -139,9 +139,9 @@ void NetworkStorageSession::deleteCookie(const Cookie&)
void NetworkStorageSession::deleteCookie(const URL& url, const String& cookie) const
{
#if TRACE_COOKIE_JAR
printf("CookieJar: delete cookie for %s (NOT IMPLEMENTED)\n", url.string().utf8().data());
printf("CookieJar: delete cookie for %s (NOT IMPLEMENTED)\n", url.string().utf8().data());
#endif
notImplemented();
notImplemented();
}
void NetworkStorageSession::deleteAllCookies()
@ -177,13 +177,13 @@ Vector<Cookie> NetworkStorageSession::getCookies(const URL&)
}
bool NetworkStorageSession::getRawCookies(const URL& firstParty,
const SameSiteInfo& sameSiteInfo, const URL& url, WTF::Optional<FrameIdentifier> frameID,
WTF::Optional<PageIdentifier> pageID, ShouldAskITP, ShouldRelaxThirdPartyCookieBlocking, Vector<Cookie>& rawCookies) const
const SameSiteInfo& sameSiteInfo, const URL& url, WTF::Optional<FrameIdentifier> frameID,
WTF::Optional<PageIdentifier> pageID, ShouldAskITP, ShouldRelaxThirdPartyCookieBlocking, Vector<Cookie>& rawCookies) const
{
#if TRACE_COOKIE_JAR
printf("CookieJar: get raw cookies for %s (NOT IMPLEMENTED)\n", url.string().utf8().data());
printf("CookieJar: get raw cookies for %s (NOT IMPLEMENTED)\n", url.string().utf8().data());
#endif
notImplemented();
notImplemented();
rawCookies.clear();
return false; // return true when implemented
@ -195,33 +195,33 @@ void NetworkStorageSession::flushCookieStore()
}
std::pair<String, bool> NetworkStorageSession::cookieRequestHeaderFieldValue(const URL& firstParty,
const SameSiteInfo& sameSiteInfo, const URL& url, WTF::Optional<FrameIdentifier> frameID,
WTF::Optional<PageIdentifier> pageID, IncludeSecureCookies includeSecureCookies, ShouldAskITP,
ShouldRelaxThirdPartyCookieBlocking) const
const SameSiteInfo& sameSiteInfo, const URL& url, WTF::Optional<FrameIdentifier> frameID,
WTF::Optional<PageIdentifier> pageID, IncludeSecureCookies includeSecureCookies, ShouldAskITP,
ShouldRelaxThirdPartyCookieBlocking) const
{
#if TRACE_COOKIE_JAR
printf("CookieJar: RequestHeaderField for %s\n", url.string().utf8().data());
printf("CookieJar: RequestHeaderField for %s\n", url.string().utf8().data());
#endif
BString result;
BUrl hUrl(url);
bool secure = false;
BString result;
BUrl hUrl(url);
bool secure = false;
const BNetworkCookie* c;
for (BNetworkCookieJar::UrlIterator it(
platformSession().GetCookieJar().GetUrlIterator(hUrl));
(c = it.Next()); ) {
// filter out secure cookies if they should be
if (c->Secure())
{
secure = true;
const BNetworkCookie* c;
for (BNetworkCookieJar::UrlIterator it(
platformSession().GetCookieJar().GetUrlIterator(hUrl));
(c = it.Next()); ) {
// filter out secure cookies if they should be
if (c->Secure())
{
secure = true;
if (includeSecureCookies == IncludeSecureCookies::No)
continue;
}
result << "; " << c->RawCookie(false);
}
result.Remove(0, 2);
continue;
}
result << "; " << c->RawCookie(false);
}
result.Remove(0, 2);
return {result, secure};
}
@ -236,13 +236,17 @@ std::pair<String, bool> NetworkStorageSession::cookieRequestHeaderFieldValue(
ShouldRelaxThirdPartyCookieBlocking::No);
}
BUrlContext& NetworkStorageSession::platformSession() const
BUrlSession& NetworkStorageSession::platformSession() const
{
static BUrlContext sDefaultContext;
return m_context ? *m_context : sDefaultContext;
static BUrlSession sDefaultSession;
if (sDefaultSession.InitCheck() != B_OK) {
// TODO: Handle this somehow? or just throw std::bad_alloc?
abort();
}
return m_context ? *m_context : sDefaultSession;
}
void NetworkStorageSession::setPlatformSession(BUrlContext* context)
void NetworkStorageSession::setPlatformSession(BUrlSession* context)
{
m_context = context;
}

View File

@ -69,7 +69,7 @@ bool ResourceHandle::start()
d->m_firstRequest.setURL(urlWithCredentials);
}
d->m_urlrequest = new BUrlProtocolHandler(d->m_context.get(), this, false);
d->m_urlrequest = new BUrlProtocolHandler(this);
if (!d->m_urlrequest->isValid())
scheduleFailure(InvalidURLFailure);
@ -107,6 +107,13 @@ void ResourceHandle::didReceiveAuthenticationChallenge(const AuthenticationChall
ASSERT(challenge.authenticationClient() == this); // Should be already set.
internal->m_currentWebChallenge = challenge;
if (challenge.previousFailureCount()) {
// The stored credentials weren't accepted, clear it from storage
// to prevent reuse if the client refuses to provide credentials.
d->m_user = String();
d->m_password = String();
}
if (client())
client()->didReceiveAuthenticationChallenge(this, challenge);
}
@ -163,6 +170,7 @@ void ResourceHandle::platformSetDefersLoading(bool defers)
d->m_job->setLoadMode(QNetworkReplyHandler::LoadMode(defers));*/
}
// TODO move to SynchronousLoaderClientHaiku.cpp
void SynchronousLoaderClient::didReceiveAuthenticationChallenge(ResourceHandle*, const AuthenticationChallenge&)
{

View File

@ -32,7 +32,7 @@
#include <String.h>
#include <Referenceable.h>
class BUrlContext;
class BUrlSession;
class BUrlRequest;
namespace WebCore {
@ -60,7 +60,7 @@ namespace WebCore {
{
}
BUrlRequest* toNetworkRequest(BUrlContext*);
BUrlRequest* toNetworkRequest(BUrlSession*);
void setCredentials(const char* username, const char* password);
void updateFromDelegatePreservingOldProperties(const ResourceRequest& delegateProvidedRequest) { *this = delegateProvidedRequest; }

View File

@ -24,7 +24,7 @@
#include "NetworkingContext.h"
#include <support/Locker.h>
#include <UrlProtocolRoster.h>
#include <UrlSession.h>
#include <UrlRequest.h>
#include <HttpRequest.h>
#include <LocaleRoster.h>
@ -32,18 +32,20 @@
namespace WebCore {
BUrlRequest* ResourceRequest::toNetworkRequest(BUrlContext* context)
BUrlRequest* ResourceRequest::toNetworkRequest(BUrlSession* session)
{
BUrlRequest* request = BUrlProtocolRoster::MakeRequest(url());
if (!session) {
m_url = WTF::aboutBlankURL();
return NULL;
}
BUrlRequest* request = session->MakeRequest(url(), nullptr);
if (!request) {
m_url = WTF::aboutBlankURL(); // This tells the ResourceLoader we failed.
return NULL;
}
if (context)
request->SetContext(context);
if (timeoutInterval() > 0)
request->SetTimeout(timeoutInterval());

View File

@ -235,12 +235,12 @@ class MediaRecorderProviderHaiku: public MediaRecorderProvider
};
BWebPage::BWebPage(BWebView* webView, BUrlContext* context)
BWebPage::BWebPage(BWebView* webView, BUrlSession* session)
: BHandler("BWebPage")
, fWebView(webView)
, fMainFrame(NULL)
, fSettings(NULL)
, fContext(context)
, fSession(session)
, fPage(NULL)
, fDumpRenderTree(NULL)
, fLoadingProgress(100)
@ -365,9 +365,9 @@ void BWebPage::SetDownloadListener(const BMessenger& listener)
sDownloadListener = listener;
}
BUrlContext* BWebPage::GetContext()
BUrlSession* BWebPage::GetSession()
{
return fContext;
return fSession;
}
void BWebPage::LoadURL(const char* urlString)

View File

@ -36,7 +36,7 @@
class BNetworkCookieJar;
class BRegion;
class BUrlContext;
class BUrlSession;
class BView;
class BWebDownload;
class BWebFrame;
@ -128,7 +128,7 @@ private:
friend class BWebView;
friend class BPrivate::WebDownloadPrivate;
BWebPage(BWebView* webView, BUrlContext* context);
BWebPage(BWebView* webView, BUrlSession* session);
// These calls are private, since they are called from the BWebView only.
void setVisible(bool visible);
@ -166,7 +166,7 @@ private:
bool modalDialog = false, bool resizable = true,
bool activate = true);
BUrlContext* GetContext();
BUrlSession* GetSession();
BRect windowFrame();
BRect windowBounds();
void setWindowBounds(const BRect& bounds);
@ -235,7 +235,7 @@ private:
BWebView* fWebView;
BWebFrame* fMainFrame;
BWebSettings* fSettings;
BUrlContext* fContext;
BUrlSession* fSession;
WebCore::Page* fPage;
WebCore::DumpRenderTreeClient* fDumpRenderTree;

View File

@ -46,7 +46,6 @@
#include <Font.h>
#include <Path.h>
#include <stdio.h>
#include <UrlContext.h>
enum {
HANDLE_SET_PERSISTENT_STORAGE_PATH = 'hspp',
@ -524,7 +523,7 @@ void BWebSettings::_HandleSetProxyInfo(BMessage* message)
// TODO there could be a cleaner way of accessing the default context from here.
RefPtr<WebCore::FrameNetworkingContextHaiku> context
= WebCore::FrameNetworkingContextHaiku::create(nullptr, nullptr);
context->context()->SetProxy(host, port);
context->session()->SetProxy(host, port);
}
void BWebSettings::_HandleApply()

View File

@ -62,7 +62,7 @@ BWebView::UserData::~UserData()
}
BWebView::BWebView(const char* name, BUrlContext* urlContext)
BWebView::BWebView(const char* name, BUrlSession* urlSession)
: BView(name, B_WILL_DRAW | B_FRAME_EVENTS | B_FULL_UPDATE_ON_RESIZE
| B_NAVIGABLE | B_PULSE_NEEDED)
, fLastMouseButtons(0)
@ -71,7 +71,7 @@ BWebView::BWebView(const char* name, BUrlContext* urlContext)
, fAutoHidePointer(false)
, fOffscreenBitmap(nullptr)
, fOffscreenView(nullptr)
, fWebPage(new BWebPage(this, urlContext))
, fWebPage(new BWebPage(this, urlSession))
, fUserData(nullptr)
{
#if USE(TEXTURE_MAPPER)

View File

@ -34,7 +34,7 @@
#include <memory>
class BUrlContext;
class BUrlSession;
class BWebPage;
namespace WebCore {
@ -53,7 +53,7 @@ public:
};
public:
BWebView(const char* name, BUrlContext* context = nullptr);
BWebView(const char* name, BUrlSession* session = nullptr);
virtual ~BWebView();
// The BWebView needs to be deleted by the BWebPage instance running

View File

@ -995,7 +995,7 @@ void FrameLoaderClientHaiku::dispatchDidClearWindowObjectInWorld(DOMWrapperWorld
Ref<FrameNetworkingContext> FrameLoaderClientHaiku::createNetworkingContext()
{
return FrameNetworkingContextHaiku::create(m_webFrame->Frame(), m_webPage->GetContext());
return FrameNetworkingContextHaiku::create(m_webFrame->Frame(), m_webPage->GetSession());
}
// #pragma mark - private

View File

@ -36,7 +36,7 @@
#include "Page.h"
#include "ResourceHandle.h"
#include <UrlContext.h>
#include <UrlSession.h>
#include <wtf/NeverDestroyed.h>
namespace WebCore {
@ -47,22 +47,22 @@ static std::unique_ptr<NetworkStorageSession>& privateSession()
return session;
}
Ref<FrameNetworkingContextHaiku> FrameNetworkingContextHaiku::create(Frame* frame, BUrlContext* context)
Ref<FrameNetworkingContextHaiku> FrameNetworkingContextHaiku::create(Frame* frame, BUrlSession* session)
{
return adoptRef(*new FrameNetworkingContextHaiku(frame, context));
return adoptRef(*new FrameNetworkingContextHaiku(frame, session));
}
FrameNetworkingContextHaiku::FrameNetworkingContextHaiku(Frame* frame, BUrlContext* context)
FrameNetworkingContextHaiku::FrameNetworkingContextHaiku(Frame* frame, BUrlSession* session)
: FrameNetworkingContext(frame)
{
storageSession()->setPlatformSession(context);
storageSession()->setPlatformSession(session);
}
FrameNetworkingContextHaiku::~FrameNetworkingContextHaiku()
{
}
BUrlContext* FrameNetworkingContextHaiku::context()
BUrlSession* FrameNetworkingContextHaiku::session()
{
return &storageSession()->platformSession();
}

View File

@ -33,22 +33,22 @@
#include <support/Locker.h>
#include <Referenceable.h>
#include <UrlContext.h>
#include <UrlSession.h>
namespace WebCore {
class FrameNetworkingContextHaiku : public WebCore::FrameNetworkingContext {
public:
static Ref<FrameNetworkingContextHaiku> create(Frame*, BUrlContext* context);
static Ref<FrameNetworkingContextHaiku> create(Frame*, BUrlSession*);
virtual ~FrameNetworkingContextHaiku();
WebCore::Frame* coreFrame() const { return frame(); }
virtual uint64_t initiatingPageID() const;
BUrlContext* context();
BUrlSession* session();
private:
FrameNetworkingContextHaiku(Frame*, BUrlContext* context);
FrameNetworkingContextHaiku(Frame*, BUrlSession*);
WebCore::NetworkStorageSession* storageSession() const override;
};

View File

@ -8,30 +8,10 @@
#include "WebPage.h"
#include <UrlRequest.h>
namespace WebCore {
class NotificationClientHaiku::SynchronousListener
: public BUrlSynchronousRequest
{
public:
SynchronousListener(BUrlRequest& request)
: BUrlSynchronousRequest(request)
{}
virtual ~SynchronousListener() {};
void DataReceived(BUrlRequest*, const char* data, off_t position,
ssize_t size) override {
result.WriteAt(position, data, size);
}
const BUrlResult& Result() const override
{ return fWrappedRequest.Result(); }
status_t _ProtocolLoop() override
{ return B_ERROR; }
BMallocIO result;
};
BNotification
NotificationClientHaiku::fromDescriptor(Notification* descriptor)
{
@ -48,19 +28,22 @@ NotificationClientHaiku::fromDescriptor(Notification* descriptor)
// TODO we should cache the data, in case the notification is re-sent
// with some changes for an update.
BUrl iconURL(descriptor->icon());
BUrlRequest* request = BUrlProtocolRoster::MakeRequest(iconURL);
if (request) {
SynchronousListener synchronous(*request);
synchronous.Perform();
synchronous.WaitUntilCompletion();
BMallocIO buffer;
BUrlSession session;
if (session.InitCheck() == B_OK) {
BUrlRequest* request = session.MakeRequest(iconURL, &buffer);
if (request) {
if (request->Run())
request->WaitForCompletion();
BBitmap* bitmap = BTranslationUtils::GetBitmap(&synchronous.result);
if (bitmap) {
notification.SetIcon(bitmap);
delete bitmap;
BBitmap* bitmap = BTranslationUtils::GetBitmap(&buffer);
if (bitmap) {
notification.SetIcon(bitmap);
delete bitmap;
}
delete request;
}
delete request;
}
notification.SetMessageID(descriptor->tag());

View File

@ -36,8 +36,7 @@
#include <Bitmap.h>
#include <TranslationUtils.h>
#include <UrlProtocolRoster.h>
#include <UrlSynchronousRequest.h>
#include <UrlSession.h>
class BWebPage;
@ -61,7 +60,7 @@ public:
void notificationObjectDestroyed(Notification*) override {}
void notificationControllerDestroyed() override {}
void requestPermission(ScriptExecutionContext*,
void requestPermission(ScriptExecutionContext*,
RefPtr<NotificationPermissionCallback>&& callback) override {
if (callback)
callback->handleEvent(NotificationPermission::Granted);
@ -74,8 +73,6 @@ public:
}
private:
class SynchronousListener;
BNotification fromDescriptor(Notification* descriptor);
};

View File

@ -60,7 +60,7 @@ LauncherApp::LauncherApp()
LauncherApp::~LauncherApp()
{
delete m_launchRefsMessage;
delete m_launchRefsMessage;
}
void LauncherApp::AboutRequested()
@ -72,23 +72,23 @@ void LauncherApp::AboutRequested()
void LauncherApp::ArgvReceived(int32 argc, char** argv)
{
for (int i = 1; i < argc; i++) {
const char* url = argv[i];
BEntry entry(argv[i], true);
BPath path;
if (entry.Exists() && entry.GetPath(&path) == B_OK)
url = path.Path();
BMessage message(LOAD_AT_STARTING);
message.AddString("url", url);
message.AddBool("new window", m_initialized || i > 1);
PostMessage(&message);
}
for (int i = 1; i < argc; i++) {
const char* url = argv[i];
BEntry entry(argv[i], true);
BPath path;
if (entry.Exists() && entry.GetPath(&path) == B_OK)
url = path.Path();
BMessage message(LOAD_AT_STARTING);
message.AddString("url", url);
message.AddBool("new window", m_initialized || i > 1);
PostMessage(&message);
}
}
void LauncherApp::ReadyToRun()
{
// Since we will essentially run the GUI...
set_thread_priority(Thread(), B_DISPLAY_PRIORITY);
// Since we will essentially run the GUI...
set_thread_priority(Thread(), B_DISPLAY_PRIORITY);
BWebPage::InitializeOnce();
BWebPage::SetCacheModel(B_WEBKIT_CACHE_MODEL_WEB_BROWSER);
@ -96,25 +96,25 @@ void LauncherApp::ReadyToRun()
mkdir("localStorage", 0755);
BWebSettings::SetPersistentStoragePath("localStorage");
BFile settingsFile;
BRect windowFrameFromSettings = m_lastWindowFrame;
if (openSettingsFile(settingsFile, B_READ_ONLY)) {
BMessage settingsArchive;
settingsArchive.Unflatten(&settingsFile);
settingsArchive.FindRect("window frame", &windowFrameFromSettings);
}
m_lastWindowFrame = windowFrameFromSettings;
BFile settingsFile;
BRect windowFrameFromSettings = m_lastWindowFrame;
if (openSettingsFile(settingsFile, B_READ_ONLY)) {
BMessage settingsArchive;
settingsArchive.Unflatten(&settingsFile);
settingsArchive.FindRect("window frame", &windowFrameFromSettings);
}
m_lastWindowFrame = windowFrameFromSettings;
m_initialized = true;
m_initialized = true;
if (m_launchRefsMessage) {
RefsReceived(m_launchRefsMessage);
delete m_launchRefsMessage;
m_launchRefsMessage = 0;
} else {
LauncherWindow* window = new LauncherWindow(m_lastWindowFrame);
window->Show();
}
if (m_launchRefsMessage) {
RefsReceived(m_launchRefsMessage);
delete m_launchRefsMessage;
m_launchRefsMessage = 0;
} else {
LauncherWindow* window = new LauncherWindow(m_lastWindowFrame, &m_session);
window->Show();
}
}
void LauncherApp::MessageReceived(BMessage* message)
@ -123,68 +123,68 @@ void LauncherApp::MessageReceived(BMessage* message)
case LOAD_AT_STARTING: {
BString url;
if (message->FindString("url", &url) != B_OK)
break;
break;
bool openNewWindow = false;
message->FindBool("new window", &openNewWindow);
LauncherWindow* webWindow = NULL;
for (int i = 0; BWindow* window = WindowAt(i); i++) {
webWindow = dynamic_cast<LauncherWindow*>(window);
if (!webWindow)
continue;
continue;
if (!openNewWindow) {
// stop at the first window
break;
// stop at the first window
break;
}
}
if (webWindow) {
// There should always be at least one window open. If not, maybe we are about
// to quit anyway...
if (openNewWindow) {
// open a new window with an offset to the last window
// There should always be at least one window open. If not, maybe we are about
// to quit anyway...
if (openNewWindow) {
// open a new window with an offset to the last window
newWindow(url);
} else {
// load the URL in the first window
} else {
// load the URL in the first window
webWindow->CurrentWebView()->LoadURL(url.String());
}
}
}
break;
}
case B_SILENT_RELAUNCH:
newWindow("");
break;
newWindow("");
break;
case NEW_WINDOW: {
BString url;
if (message->FindString("url", &url) != B_OK)
break;
newWindow(url);
break;
BString url;
if (message->FindString("url", &url) != B_OK)
break;
newWindow(url);
break;
}
case WINDOW_OPENED:
m_windowCount++;
break;
m_windowCount++;
break;
case WINDOW_CLOSED:
m_windowCount--;
m_windowCount--;
message->FindRect("window frame", &m_lastWindowFrame);
if (m_windowCount <= 0)
PostMessage(B_QUIT_REQUESTED);
break;
if (m_windowCount <= 0)
PostMessage(B_QUIT_REQUESTED);
break;
case B_SAVE_REQUESTED:
{
entry_ref dir;
message->FindRef("directory", &dir);
BString name = message->FindString("name");
case B_SAVE_REQUESTED:
{
entry_ref dir;
message->FindRef("directory", &dir);
BString name = message->FindString("name");
BDirectory saveTo(&dir);
BFile file(&saveTo, name,
B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE);
BFile file(&saveTo, name,
B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE);
BWebPage* page = NULL;
BWebPage* page = NULL;
message->FindPointer("page", (void**)&page);
page->GetContentsAsMHTML(file);
break;
}
break;
}
default:
BApplication::MessageReceived(message);
break;
@ -193,24 +193,24 @@ void LauncherApp::MessageReceived(BMessage* message)
void LauncherApp::RefsReceived(BMessage* message)
{
if (!m_initialized) {
delete m_launchRefsMessage;
m_launchRefsMessage = new BMessage(*message);
return;
}
if (!m_initialized) {
delete m_launchRefsMessage;
m_launchRefsMessage = new BMessage(*message);
return;
}
entry_ref ref;
for (int32 i = 0; message->FindRef("refs", i, &ref) == B_OK; i++) {
BEntry entry(&ref, true);
if (!entry.Exists())
continue;
BPath path;
if (entry.GetPath(&path) != B_OK)
continue;
BString url;
url << path.Path();
newWindow(url);
}
entry_ref ref;
for (int32 i = 0; message->FindRef("refs", i, &ref) == B_OK; i++) {
BEntry entry(&ref, true);
if (!entry.Exists())
continue;
BPath path;
if (entry.GetPath(&path) != B_OK)
continue;
BString url;
url << path.Path();
newWindow(url);
}
}
bool LauncherApp::QuitRequested()
@ -218,51 +218,51 @@ bool LauncherApp::QuitRequested()
for (int i = 0; BWindow* window = WindowAt(i); i++) {
LauncherWindow* webWindow = dynamic_cast<LauncherWindow*>(window);
if (!webWindow)
continue;
continue;
if (!webWindow->Lock())
continue;
continue;
if (webWindow->QuitRequested()) {
m_lastWindowFrame = webWindow->Frame();
m_lastWindowFrame = webWindow->Frame();
webWindow->CurrentWebView()->Shutdown();
delete webWindow->CurrentWebView();
webWindow->Quit();
i--;
webWindow->Quit();
i--;
} else {
webWindow->Unlock();
return false;
webWindow->Unlock();
return false;
}
}
BFile settingsFile;
if (openSettingsFile(settingsFile, B_CREATE_FILE | B_ERASE_FILE | B_WRITE_ONLY)) {
BMessage settingsArchive;
settingsArchive.AddRect("window frame", m_lastWindowFrame);
settingsArchive.Flatten(&settingsFile);
}
BFile settingsFile;
if (openSettingsFile(settingsFile, B_CREATE_FILE | B_ERASE_FILE | B_WRITE_ONLY)) {
BMessage settingsArchive;
settingsArchive.AddRect("window frame", m_lastWindowFrame);
settingsArchive.Flatten(&settingsFile);
}
return true;
}
bool LauncherApp::openSettingsFile(BFile& file, uint32 mode)
{
BPath path;
if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) != B_OK
|| path.Append("HaikuLauncher") != B_OK) {
return false;
}
return file.SetTo(path.Path(), mode) == B_OK;
BPath path;
if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) != B_OK
|| path.Append("HaikuLauncher") != B_OK) {
return false;
}
return file.SetTo(path.Path(), mode) == B_OK;
}
void LauncherApp::newWindow(const BString& url)
{
m_lastWindowFrame.OffsetBy(20, 20);
if (!BScreen().Frame().Contains(m_lastWindowFrame))
m_lastWindowFrame.OffsetTo(50, 50);
m_lastWindowFrame.OffsetBy(20, 20);
if (!BScreen().Frame().Contains(m_lastWindowFrame))
m_lastWindowFrame.OffsetTo(50, 50);
LauncherWindow* window = new LauncherWindow(m_lastWindowFrame);
window->Show();
if (url.Length())
window->CurrentWebView()->LoadURL(url.String());
LauncherWindow* window = new LauncherWindow(m_lastWindowFrame, &m_session);
window->Show();
if (url.Length())
window->CurrentWebView()->LoadURL(url.String());
}
// #pragma mark -

View File

@ -32,6 +32,7 @@
#include <support/Locker.h>
#include <Application.h>
#include <Rect.h>
#include <UrlSession.h>
class BFile;
class LauncherWindow;
@ -49,13 +50,15 @@ public:
virtual bool QuitRequested();
private:
bool openSettingsFile(BFile& file, uint32 mode);
void newWindow(const BString& url);
bool openSettingsFile(BFile& file, uint32 mode);
void newWindow(const BString& url);
int m_windowCount;
BRect m_lastWindowFrame;
BMessage* m_launchRefsMessage;
bool m_initialized;
BUrlSession m_session;
};
extern const char* kApplicationSignature;

View File

@ -57,9 +57,9 @@
#include <stdio.h>
enum {
OPEN_LOCATION = 'open',
OPEN_INSPECTOR = 'insp',
SAVE_PAGE = 'save',
OPEN_LOCATION = 'open',
OPEN_INSPECTOR = 'insp',
SAVE_PAGE = 'save',
GO_BACK = 'goba',
GO_FORWARD = 'gofo',
STOP = 'stop',
@ -71,21 +71,21 @@ enum {
TEXT_SIZE_RESET = 'tsrs',
};
LauncherWindow::LauncherWindow(BRect frame, ToolbarPolicy toolbarPolicy)
LauncherWindow::LauncherWindow(BRect frame, BUrlSession* session, ToolbarPolicy toolbarPolicy)
: BWebWindow(frame, "HaikuLauncher",
B_DOCUMENT_WINDOW_LOOK, B_NORMAL_WINDOW_FEEL,
B_AUTO_UPDATE_SIZE_LIMITS | B_ASYNCHRONOUS_CONTROLS)
{
init(new BWebView("web view"), toolbarPolicy);
init(new BWebView("web view", session), toolbarPolicy);
}
LauncherWindow::LauncherWindow(BRect frame, BWebView* webView,
ToolbarPolicy toolbarPolicy)
ToolbarPolicy toolbarPolicy)
: BWebWindow(frame, "HaikuLauncher",
B_DOCUMENT_WINDOW_LOOK, B_NORMAL_WINDOW_FEEL,
B_AUTO_UPDATE_SIZE_LIMITS | B_ASYNCHRONOUS_CONTROLS)
{
init(webView, toolbarPolicy);
init(webView, toolbarPolicy);
}
LauncherWindow::~LauncherWindow()
@ -95,23 +95,23 @@ LauncherWindow::~LauncherWindow()
void LauncherWindow::DispatchMessage(BMessage* message, BHandler* target)
{
if (m_url && message->what == B_KEY_DOWN && target == m_url->TextView()) {
// Handle B_RETURN in the URL text control. This is the easiest
// way to react *only* when the user presses the return key in the
// address bar, as opposed to trying to load whatever is in there when
// the text control just goes out of focus.
const char* bytes;
if (message->FindString("bytes", &bytes) == B_OK
&& bytes[0] == B_RETURN) {
// Do it in such a way that the user sees the Go-button go down.
m_goButton->SetValue(B_CONTROL_ON);
UpdateIfNeeded();
m_goButton->Invoke();
snooze(1000);
m_goButton->SetValue(B_CONTROL_OFF);
}
}
BWebWindow::DispatchMessage(message, target);
if (m_url && message->what == B_KEY_DOWN && target == m_url->TextView()) {
// Handle B_RETURN in the URL text control. This is the easiest
// way to react *only* when the user presses the return key in the
// address bar, as opposed to trying to load whatever is in there when
// the text control just goes out of focus.
const char* bytes;
if (message->FindString("bytes", &bytes) == B_OK
&& bytes[0] == B_RETURN) {
// Do it in such a way that the user sees the Go-button go down.
m_goButton->SetValue(B_CONTROL_ON);
UpdateIfNeeded();
m_goButton->Invoke();
snooze(1000);
m_goButton->SetValue(B_CONTROL_OFF);
}
}
BWebWindow::DispatchMessage(message, target);
}
void LauncherWindow::MessageReceived(BMessage* message)
@ -119,36 +119,36 @@ void LauncherWindow::MessageReceived(BMessage* message)
switch (message->what) {
case OPEN_LOCATION:
if (m_url) {
if (m_url->TextView()->IsFocus())
m_url->TextView()->SelectAll();
else
m_url->MakeFocus(true);
if (m_url->TextView()->IsFocus())
m_url->TextView()->SelectAll();
else
m_url->MakeFocus(true);
}
break;
break;
case OPEN_INSPECTOR: {
// FIXME: wouldn't the view better be in the same window?
BRect frame = Frame();
frame.OffsetBy(20, 20);
LauncherWindow* inspectorWindow = new LauncherWindow(frame);
LauncherWindow* inspectorWindow = new LauncherWindow(frame, (BUrlSession*)NULL);
inspectorWindow->Show();
CurrentWebView()->SetInspectorView(inspectorWindow->CurrentWebView());
break;
}
case SAVE_PAGE: {
BMessage* message = new BMessage(B_SAVE_REQUESTED);
message->AddPointer("page", CurrentWebView()->WebPage());
case SAVE_PAGE: {
BMessage* message = new BMessage(B_SAVE_REQUESTED);
message->AddPointer("page", CurrentWebView()->WebPage());
if (m_saveFilePanel == NULL) {
m_saveFilePanel = new BFilePanel(B_SAVE_PANEL, NULL, NULL,
m_saveFilePanel = new BFilePanel(B_SAVE_PANEL, NULL, NULL,
B_DIRECTORY_NODE, false);
}
m_saveFilePanel->SetSaveText(CurrentWebView()->WebPage()->MainFrameTitle());
m_saveFilePanel->SetMessage(message);
m_saveFilePanel->Show();
break;
}
m_saveFilePanel->Show();
break;
}
case RELOAD:
CurrentWebView()->Reload();
@ -156,7 +156,7 @@ void LauncherWindow::MessageReceived(BMessage* message)
case GOTO_URL: {
BString url;
if (message->FindString("url", &url) != B_OK)
url = m_url->Text();
url = m_url->Text();
CurrentWebView()->LoadURL(url.String());
break;
}
@ -239,12 +239,12 @@ void LauncherWindow::NewWindowRequested(const BString& url, bool primaryAction)
}
void LauncherWindow::NewPageCreated(BWebView* view, BRect windowFrame,
bool modalDialog, bool resizable, bool activate)
bool modalDialog, bool resizable, bool activate)
{
if (!windowFrame.IsValid())
windowFrame = Frame().OffsetByCopy(10, 10);
LauncherWindow* window = new LauncherWindow(windowFrame, view, HaveToolbar);
window->Show();
if (!windowFrame.IsValid())
windowFrame = Frame().OffsetByCopy(10, 10);
LauncherWindow* window = new LauncherWindow(windowFrame, view, HaveToolbar);
window->Show();
}
void LauncherWindow::LoadNegotiating(const BString& url, BWebView* view)
@ -256,7 +256,7 @@ void LauncherWindow::LoadNegotiating(const BString& url, BWebView* view)
void LauncherWindow::LoadCommitted(const BString& url, BWebView* view)
{
// This hook is invoked when the load is commited.
// This hook is invoked when the load is commited.
if (m_url)
m_url->SetText(url.String());
@ -343,21 +343,21 @@ void LauncherWindow::NavigationCapabilitiesChanged(bool canGoBackward,
bool
LauncherWindow::AuthenticationChallenge(BString message, BString& inOutUser,
BString& inOutPassword, bool& inOutRememberCredentials,
uint32 failureCount, BWebView* view)
BString& inOutPassword, bool& inOutRememberCredentials,
uint32 failureCount, BWebView* view)
{
AuthenticationPanel* panel = new AuthenticationPanel(Frame());
// Panel auto-destructs.
bool success = panel->getAuthentication(message, inOutUser, inOutPassword,
inOutRememberCredentials, failureCount > 0, inOutUser, inOutPassword,
&inOutRememberCredentials);
return success;
AuthenticationPanel* panel = new AuthenticationPanel(Frame());
// Panel auto-destructs.
bool success = panel->getAuthentication(message, inOutUser, inOutPassword,
inOutRememberCredentials, failureCount > 0, inOutUser, inOutPassword,
&inOutRememberCredentials);
return success;
}
void LauncherWindow::init(BWebView* webView, ToolbarPolicy toolbarPolicy)
{
SetCurrentWebView(webView);
SetCurrentWebView(webView);
if (toolbarPolicy == HaveToolbar) {
// Menu
@ -370,7 +370,7 @@ void LauncherWindow::init(BWebView* webView, ToolbarPolicy toolbarPolicy)
newItem->SetTarget(be_app);
menu->AddItem(new BMenuItem("Open location", new BMessage(OPEN_LOCATION), 'L'));
menu->AddItem(new BMenuItem("Inspect page", new BMessage(OPEN_INSPECTOR), 'I'));
menu->AddItem(new BMenuItem("Save page", new BMessage(SAVE_PAGE), 'S'));
menu->AddItem(new BMenuItem("Save page", new BMessage(SAVE_PAGE), 'S'));
menu->AddSeparatorItem();
menu->AddItem(new BMenuItem("Close", new BMessage(B_QUIT_REQUESTED), 'W', B_SHIFT_KEY));
BMenuItem* quitItem = new BMenuItem("Quit", new BMessage(B_QUIT_REQUESTED), 'Q');

View File

@ -43,6 +43,7 @@ class BStatusBar;
class BStringView;
class BTextControl;
class BWebView;
class BUrlSession;
enum ToolbarPolicy {
HaveToolbar,
@ -57,7 +58,7 @@ enum {
class LauncherWindow : public BWebWindow {
public:
LauncherWindow(BRect frame, ToolbarPolicy = HaveToolbar);
LauncherWindow(BRect frame, BUrlSession*, ToolbarPolicy = HaveToolbar);
LauncherWindow(BRect frame, BWebView* view, ToolbarPolicy = HaveToolbar);
virtual ~LauncherWindow();