libbnetapi: fix access to HTTP headers
The asynchronous listener had no reliable way to access HTTP result and headers from the callbacks. As the callbacks are triggered asynchronously, they can be run after the request has carried on and, for example, followed an HTTP redirect, clearing its internal state. The HeadersReceived callback now passes a reference to BUrlResult for the request. There are two cases: - Synchronous listener: passes a reference to the request's results directly - Asynchronous listener: archives a copy of the result into the notification message, and passes a reference to the unarchived copy. Unfortunately this comes with several ABI and API breakages: - Change to the prototype of HeadersReceived() - Change to the class hierarchy of BUrlResult (implements BArchivable) All users of HTTP requests will need to be updated if they implemented in HeadersReceived or used BUrlResult.
This commit is contained in:
parent
ab880b1753
commit
f9e1854f19
@ -7,6 +7,7 @@
|
||||
|
||||
|
||||
#include <List.h>
|
||||
#include <Message.h>
|
||||
#include <String.h>
|
||||
|
||||
|
||||
@ -66,6 +67,10 @@ public:
|
||||
bool AddHeader(const char* name,
|
||||
int32 value);
|
||||
|
||||
// Archiving
|
||||
void PopulateFromArchive(BMessage*);
|
||||
void Archive(BMessage*) const;
|
||||
|
||||
// Header deletion
|
||||
void Clear();
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010 Haiku Inc. All rights reserved.
|
||||
* Copyright 2010-2017 Haiku Inc. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef _B_HTTP_RESULT_H_
|
||||
@ -22,12 +22,13 @@ class BHttpResult: public BUrlResult {
|
||||
|
||||
public:
|
||||
BHttpResult(const BUrl& url);
|
||||
BHttpResult(BMessage*);
|
||||
BHttpResult(const BHttpResult& other);
|
||||
~BHttpResult();
|
||||
|
||||
|
||||
// Result parameters modifications
|
||||
void SetUrl(const BUrl& url);
|
||||
|
||||
|
||||
// Result parameters access
|
||||
const BUrl& Url() const;
|
||||
BString ContentType() const;
|
||||
@ -37,13 +38,15 @@ public:
|
||||
const BHttpHeaders& Headers() const;
|
||||
const BString& StatusText() const;
|
||||
int32 StatusCode() const;
|
||||
|
||||
|
||||
// Result tests
|
||||
bool HasHeaders() const;
|
||||
|
||||
|
||||
// Overloaded members
|
||||
BHttpResult& operator=(const BHttpResult& other);
|
||||
|
||||
BHttpResult& operator=(const BHttpResult& other);
|
||||
|
||||
virtual status_t Archive(BMessage*, bool) const;
|
||||
static BArchivable* Instantiate(BMessage*);
|
||||
private:
|
||||
BUrl fUrl;
|
||||
|
||||
|
@ -44,7 +44,8 @@ public:
|
||||
virtual void HostnameResolved(BUrlRequest* caller,
|
||||
const char* ip);
|
||||
virtual void ResponseStarted(BUrlRequest* caller);
|
||||
virtual void HeadersReceived(BUrlRequest* caller);
|
||||
virtual void HeadersReceived(BUrlRequest* caller,
|
||||
const BUrlResult& result);
|
||||
virtual void DataReceived(BUrlRequest* caller,
|
||||
const char* data, off_t position,
|
||||
ssize_t size);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010 Haiku Inc. All rights reserved.
|
||||
* Copyright 2010-2017 Haiku Inc. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef _B_URL_PROTOCOL_LISTENER_H_
|
||||
@ -9,6 +9,8 @@
|
||||
#include <stddef.h>
|
||||
#include <cstdlib>
|
||||
|
||||
#include <UrlResult.h>
|
||||
|
||||
|
||||
class BCertificate;
|
||||
class BUrlRequest;
|
||||
@ -61,7 +63,8 @@ public:
|
||||
Called when all the server response metadata (such as headers) have
|
||||
been read and parsed.
|
||||
*/
|
||||
virtual void HeadersReceived(BUrlRequest* caller);
|
||||
virtual void HeadersReceived(BUrlRequest* caller,
|
||||
const BUrlResult& result);
|
||||
|
||||
/**
|
||||
DataReceived(data, position, size)
|
||||
|
@ -1,26 +1,33 @@
|
||||
/*
|
||||
* Copyright 2010 Haiku Inc. All rights reserved.
|
||||
* Copyright 2010-2017 Haiku Inc. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef _B_URL_RESULT_H_
|
||||
#define _B_URL_RESULT_H_
|
||||
|
||||
|
||||
#include <Archivable.h>
|
||||
#include <String.h>
|
||||
|
||||
|
||||
class BUrlResult {
|
||||
class BUrlResult: public BArchivable {
|
||||
public:
|
||||
BUrlResult();
|
||||
BUrlResult(BMessage*);
|
||||
virtual ~BUrlResult();
|
||||
|
||||
virtual status_t Archive(BMessage*, bool) const;
|
||||
|
||||
void SetContentType(BString contentType);
|
||||
void SetLength(size_t length);
|
||||
|
||||
virtual BString ContentType() const;
|
||||
virtual size_t Length() const;
|
||||
|
||||
static BArchivable* Instantiate(BMessage*);
|
||||
|
||||
private:
|
||||
BString fContentType;
|
||||
BString fCharset;
|
||||
size_t fLength;
|
||||
};
|
||||
|
||||
|
@ -24,7 +24,8 @@ public:
|
||||
virtual void HostnameResolved(BUrlRequest* caller,
|
||||
const char* ip);
|
||||
virtual void ResponseStarted(BUrlRequest* caller);
|
||||
virtual void HeadersReceived(BUrlRequest* caller);
|
||||
virtual void HeadersReceived(BUrlRequest* caller,
|
||||
const BUrlResult& result);
|
||||
virtual void DataReceived(BUrlRequest* caller,
|
||||
const char* data, off_t position,
|
||||
ssize_t size);
|
||||
|
@ -210,7 +210,7 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
virtual void HeadersReceived(BUrlRequest* caller)
|
||||
virtual void HeadersReceived(BUrlRequest* caller, const BUrlResult& result)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -118,7 +118,7 @@ BDataRequest::_ProtocolLoop()
|
||||
fResult.SetLength(length);
|
||||
|
||||
if (fListener != NULL) {
|
||||
fListener->HeadersReceived(this);
|
||||
fListener->HeadersReceived(this, fResult);
|
||||
fListener->DownloadProgress(this, length, length);
|
||||
if (length > 0)
|
||||
fListener->DataReceived(this, payload, 0, length);
|
||||
|
@ -77,7 +77,7 @@ BFileRequest::_ProtocolLoop()
|
||||
return error;
|
||||
fResult.SetLength(size);
|
||||
|
||||
fListener->HeadersReceived(this);
|
||||
fListener->HeadersReceived(this, fResult);
|
||||
|
||||
ssize_t chunkSize;
|
||||
char chunk[4096];
|
||||
@ -113,7 +113,7 @@ BFileRequest::_ProtocolLoop()
|
||||
|
||||
if (fListener != NULL) {
|
||||
fListener->ConnectionOpened(this);
|
||||
fListener->HeadersReceived(this);
|
||||
fListener->HeadersReceived(this, fResult);
|
||||
|
||||
// Add a parent directory entry.
|
||||
fListener->DataReceived(this, "+/,\t..\r\n", transferredSize, 8);
|
||||
|
@ -325,7 +325,6 @@ BGopherRequest::_ProtocolLoop()
|
||||
// continue parsing the error text anyway
|
||||
// but it won't look good
|
||||
}
|
||||
|
||||
|
||||
// now we probably have correct data
|
||||
dataValidated = true;
|
||||
@ -334,11 +333,6 @@ BGopherRequest::_ProtocolLoop()
|
||||
if (fListener != NULL)
|
||||
fListener->ResponseStarted(this);
|
||||
|
||||
// we don't really have headers but well...
|
||||
//! ProtocolHook:HeadersReceived
|
||||
if (fListener != NULL)
|
||||
fListener->HeadersReceived(this);
|
||||
|
||||
// now we can assign MIME type if we know it
|
||||
const char *mime = "application/octet-stream";
|
||||
for (i = 0; gopher_type_map[i].type != GOPHER_TYPE_NONE; i++) {
|
||||
@ -348,6 +342,11 @@ BGopherRequest::_ProtocolLoop()
|
||||
}
|
||||
}
|
||||
fResult.SetContentType(mime);
|
||||
|
||||
// we don't really have headers but well...
|
||||
//! ProtocolHook:HeadersReceived
|
||||
if (fListener != NULL)
|
||||
fListener->HeadersReceived(this, fResult);
|
||||
}
|
||||
|
||||
if (_NeedsParsing())
|
||||
|
@ -245,6 +245,42 @@ BHttpHeaders::AddHeader(const char* name, int32 value)
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark Archiving
|
||||
|
||||
|
||||
void
|
||||
BHttpHeaders::PopulateFromArchive(BMessage* archive)
|
||||
{
|
||||
Clear();
|
||||
|
||||
int32 index = 0;
|
||||
char* nameFound;
|
||||
for(;;) {
|
||||
if (archive->GetInfo(B_STRING_TYPE, index, &nameFound, NULL) != B_OK)
|
||||
return;
|
||||
|
||||
BString value = archive->FindString(nameFound);
|
||||
AddHeader(nameFound, value);
|
||||
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
BHttpHeaders::Archive(BMessage* message) const
|
||||
{
|
||||
int32 count = CountHeaders();
|
||||
int32 i;
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
BHttpHeader& header = HeaderAt(i);
|
||||
message->AddString(header.Name(), header.Value());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark Header deletion
|
||||
|
||||
|
||||
|
@ -613,7 +613,7 @@ BHttpRequest::_MakeRequest()
|
||||
|
||||
//! ProtocolHook:HeadersReceived
|
||||
if (fListener != NULL)
|
||||
fListener->HeadersReceived(this);
|
||||
fListener->HeadersReceived(this, fResult);
|
||||
|
||||
// Parse received cookies
|
||||
if (fContext != NULL) {
|
||||
@ -696,8 +696,6 @@ BHttpRequest::_MakeRequest()
|
||||
}
|
||||
|
||||
chunkSize = strtol(chunkHeader.String(), NULL, 16);
|
||||
PRINT(("BHP[%p] Chunk %s=%ld\n", this,
|
||||
chunkHeader.String(), chunkSize));
|
||||
if (chunkSize == 0)
|
||||
fRequestStatus = kRequestContentReceived;
|
||||
|
||||
|
@ -1,9 +1,10 @@
|
||||
/*
|
||||
* Copyright 2010 Haiku Inc. All rights reserved.
|
||||
* Copyright 2010-2017 Haiku Inc. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Christophe Huriaux, c.huriaux@gmail.com
|
||||
* Adrien Destugues, pulkomandy@pulkomandy.tk
|
||||
*/
|
||||
|
||||
|
||||
@ -23,6 +24,20 @@ BHttpResult::BHttpResult(const BUrl& url)
|
||||
}
|
||||
|
||||
|
||||
BHttpResult::BHttpResult(BMessage* archive)
|
||||
:
|
||||
BUrlResult(archive)
|
||||
{
|
||||
fUrl = archive->FindString("http:url");
|
||||
fStatusCode = archive->FindInt32("http:statusCode");
|
||||
fStatusString = archive->FindString("http:statusString");
|
||||
|
||||
BMessage headers;
|
||||
archive->FindMessage("http:headers", &headers);
|
||||
fHeaders.PopulateFromArchive(&headers);
|
||||
}
|
||||
|
||||
|
||||
BHttpResult::BHttpResult(const BHttpResult& other)
|
||||
:
|
||||
fUrl(other.fUrl),
|
||||
@ -114,7 +129,7 @@ BHttpResult::operator=(const BHttpResult& other)
|
||||
{
|
||||
if (this == &other)
|
||||
return *this;
|
||||
|
||||
|
||||
fUrl = other.fUrl;
|
||||
fHeaders = other.fHeaders;
|
||||
fStatusCode = other.fStatusCode;
|
||||
@ -122,3 +137,34 @@ BHttpResult::operator=(const BHttpResult& other)
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
BHttpResult::Archive(BMessage* target, bool deep) const
|
||||
{
|
||||
status_t result = BUrlResult::Archive(target, deep);
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
target->AddString("http:url", fUrl);
|
||||
target->AddInt32("http:statusCode", fStatusCode);
|
||||
target->AddString("http:statusString", fStatusString);
|
||||
|
||||
BMessage headers;
|
||||
fHeaders.Archive(&headers);
|
||||
target->AddMessage("http:headers", &headers);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
/*static*/ BArchivable*
|
||||
BHttpResult::Instantiate(BMessage* archive)
|
||||
{
|
||||
if (!validate_instantiation(archive, "BHttpResult"))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return new BHttpResult(archive);
|
||||
}
|
||||
|
@ -1,22 +1,28 @@
|
||||
/*
|
||||
* Copyright 2010 Haiku Inc. All rights reserved.
|
||||
* Copyright 2010-2017 Haiku Inc. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Christophe Huriaux, c.huriaux@gmail.com
|
||||
* Adrien Destugues, pulkomandy@pulkomandy.tk
|
||||
*/
|
||||
|
||||
|
||||
#include <UrlProtocolAsynchronousListener.h>
|
||||
|
||||
#include <new>
|
||||
|
||||
#include <AppKit.h>
|
||||
#include <UrlProtocolAsynchronousListener.h>
|
||||
#include <Archivable.h>
|
||||
#include <Debug.h>
|
||||
#include <String.h>
|
||||
#include <UrlResult.h>
|
||||
|
||||
|
||||
extern const char* kUrlProtocolMessageType;
|
||||
extern const char* kUrlProtocolCaller;
|
||||
|
||||
|
||||
BUrlProtocolAsynchronousListener::BUrlProtocolAsynchronousListener(
|
||||
bool transparent)
|
||||
:
|
||||
@ -92,7 +98,14 @@ BUrlProtocolAsynchronousListener::MessageReceived(BMessage* message)
|
||||
break;
|
||||
|
||||
case B_URL_PROTOCOL_HEADERS_RECEIVED:
|
||||
HeadersReceived(caller);
|
||||
{
|
||||
BMessage archive;
|
||||
message->FindMessage("url:result", &archive);
|
||||
BUrlResult* result = dynamic_cast<BUrlResult*>(
|
||||
instantiate_object(&archive));
|
||||
HeadersReceived(caller, *result);
|
||||
delete result;
|
||||
}
|
||||
break;
|
||||
|
||||
case B_URL_PROTOCOL_DATA_RECEIVED:
|
||||
|
@ -1,14 +1,17 @@
|
||||
/*
|
||||
* Copyright 2010 Haiku Inc. All rights reserved.
|
||||
* Copyright 2010-2017 Haiku Inc. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Christophe Huriaux, c.huriaux@gmail.com
|
||||
* Adrien Destugues, pulkomandy@pulkomandy.tk
|
||||
*/
|
||||
|
||||
|
||||
#include <UrlProtocolDispatchingListener.h>
|
||||
|
||||
#include <Debug.h>
|
||||
#include <UrlResult.h>
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
@ -27,7 +30,7 @@ BUrlProtocolDispatchingListener::BUrlProtocolDispatchingListener
|
||||
|
||||
BUrlProtocolDispatchingListener::BUrlProtocolDispatchingListener
|
||||
(const BMessenger& messenger)
|
||||
:
|
||||
:
|
||||
fMessenger(messenger)
|
||||
{
|
||||
}
|
||||
@ -66,9 +69,17 @@ BUrlProtocolDispatchingListener::ResponseStarted(BUrlRequest* caller)
|
||||
|
||||
|
||||
void
|
||||
BUrlProtocolDispatchingListener::HeadersReceived(BUrlRequest* caller)
|
||||
BUrlProtocolDispatchingListener::HeadersReceived(BUrlRequest* caller,
|
||||
const BUrlResult& result)
|
||||
{
|
||||
/* The URL request does not keep the headers valid after calling this
|
||||
* method. For asynchronous delivery to work, we need to archive them
|
||||
* into the message. */
|
||||
BMessage message(B_URL_PROTOCOL_NOTIFICATION);
|
||||
BMessage archive;
|
||||
result.Archive(&archive, true);
|
||||
message.AddMessage("url:result", &archive);
|
||||
|
||||
_SendMessage(&message, B_URL_PROTOCOL_HEADERS_RECEIVED, caller);
|
||||
}
|
||||
|
||||
@ -157,7 +168,7 @@ BUrlProtocolDispatchingListener::CertificateVerificationFailed(
|
||||
|
||||
|
||||
void
|
||||
BUrlProtocolDispatchingListener::_SendMessage(BMessage* message,
|
||||
BUrlProtocolDispatchingListener::_SendMessage(BMessage* message,
|
||||
int8 notification, BUrlRequest* caller)
|
||||
{
|
||||
ASSERT(message != NULL);
|
||||
|
@ -1,9 +1,10 @@
|
||||
/*
|
||||
* Copyright 2010 Haiku Inc. All rights reserved.
|
||||
* Copyright 2010-2017 Haiku Inc. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Christophe Huriaux, c.huriaux@gmail.com
|
||||
* Adrien Destugues, pulkomandy@pulkomandy.tk
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
@ -42,7 +43,7 @@ BUrlProtocolListener::ResponseStarted(BUrlRequest*)
|
||||
|
||||
|
||||
void
|
||||
BUrlProtocolListener::HeadersReceived(BUrlRequest*)
|
||||
BUrlProtocolListener::HeadersReceived(BUrlRequest*, const BUrlResult& result)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013 Haiku Inc. All rights reserved.
|
||||
* Copyright 2013-2017 Haiku Inc. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
@ -10,11 +10,44 @@
|
||||
#include <UrlResult.h>
|
||||
|
||||
|
||||
BUrlResult::BUrlResult()
|
||||
:
|
||||
BArchivable(),
|
||||
fContentType(),
|
||||
fLength(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
BUrlResult::BUrlResult(BMessage* archive)
|
||||
:
|
||||
BArchivable(archive)
|
||||
{
|
||||
fContentType = archive->FindString("ContentType");
|
||||
fLength = archive->FindInt32("Length");
|
||||
}
|
||||
|
||||
|
||||
BUrlResult::~BUrlResult()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
BUrlResult::Archive(BMessage* archive, bool deep) const
|
||||
{
|
||||
status_t result = BArchivable::Archive(archive, deep);
|
||||
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
archive->AddString("ContentType", fContentType);
|
||||
archive->AddInt32("Length", fLength);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
BUrlResult::SetContentType(BString contentType)
|
||||
{
|
||||
@ -41,3 +74,12 @@ BUrlResult::Length() const
|
||||
{
|
||||
return fLength;
|
||||
}
|
||||
|
||||
|
||||
/*static*/ BArchivable*
|
||||
BUrlResult::Instantiate(BMessage* archive)
|
||||
{
|
||||
if (!validate_instantiation(archive, "BUrlResult"))
|
||||
return NULL;
|
||||
return new BUrlResult(archive);
|
||||
}
|
||||
|
@ -71,7 +71,7 @@ BUrlSynchronousRequest::ResponseStarted(BUrlRequest*)
|
||||
|
||||
|
||||
void
|
||||
BUrlSynchronousRequest::HeadersReceived(BUrlRequest*)
|
||||
BUrlSynchronousRequest::HeadersReceived(BUrlRequest*, const BUrlResult& result)
|
||||
{
|
||||
PRINT(("SynchronousRequest::HeadersReceived()\n"));
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user