Refactor UrlRequest/UrlProtocol in the Service Kit

* Remove the BUrlRequest class, which was only delegating work to
BUrlProtocol and subclasses
 * Rename BUrlProtocol to BUrlRequest, and BUrlRequestHttp to BHttpRequest
 * Creating a request is now done through the BUrlProtocolRoster. For
now there is just a static MakeRequest method, this will be completed
when we get to actually allowing add-ons to provide different request
handlers.

This allows cleanup of the API for requests:
 * Remove the universal SetOption method with constants, and have
dedicated setters for each protocol option.
 * Setters can now have multiple parameters, for example you can give
BHTTPRequest a BDataIO and a known size
 * In this case, the BHttpRequest will not use HTTP chunked transfers,
which were always used before and made most servers unhappy (tested and
failed with lighttpd, google accounts and github).
This commit is contained in:
Adrien Destugues
2013-10-08 11:42:05 +02:00
parent 65e2db9f84
commit afd547b368
21 changed files with 596 additions and 843 deletions
+1 -2
View File
@@ -60,8 +60,7 @@ public:
// Change behavior // Change behavior
status_t MarkAsFile(const BString& filename, status_t MarkAsFile(const BString& filename,
const BString& mimeType); const BString& mimeType = "");
status_t MarkAsFile(const BString& filename);
void UnmarkAsFile(); void UnmarkAsFile();
status_t CopyBuffer(); status_t CopyBuffer();
@@ -14,22 +14,34 @@
#include <HttpHeaders.h> #include <HttpHeaders.h>
#include <NetBuffer.h> #include <NetBuffer.h>
#include <NetworkAddress.h> #include <NetworkAddress.h>
#include <UrlProtocol.h> #include <UrlRequest.h>
class BAbstractSocket; class BAbstractSocket;
class BUrlProtocolHttp : public BUrlProtocol { class BHttpRequest : public BUrlRequest {
public: public:
BUrlProtocolHttp(BUrl& url, bool ssl = false, BHttpRequest(const BUrl& url,
BUrlResult& result, bool ssl = false,
const char *protocolName = "HTTP", const char *protocolName = "HTTP",
BUrlProtocolListener* listener = NULL, BUrlProtocolListener* listener = NULL,
BUrlContext* context = NULL, BUrlContext* context = NULL);
BUrlResult* result = NULL); virtual ~BHttpRequest();
virtual ~BUrlProtocolHttp();
virtual status_t SetOption(uint32 option, void* value); void SetMethod(int8 method);
void SetFollowLocation(bool follow);
void SetMaxRedirections(int8 maxRedirections);
void SetReferrer(const BString& referrer);
void SetUserAgent(const BString& agent);
void SetHeaders(BHttpHeaders* headers);
void SetDiscardData(bool discard);
void SetDisableListener(bool disable);
void SetAutoReferrer(bool enable);
void SetPostFields(BHttpForm* fields);
void SetInputData(BDataIO* data, ssize_t size = -1);
void SetUserName(const BString& name);
void SetPassword(const BString& password);
static bool IsInformationalStatusCode(int16 code); static bool IsInformationalStatusCode(int16 code);
static bool IsSuccessStatusCode(int16 code); static bool IsSuccessStatusCode(int16 code);
@@ -89,6 +101,7 @@ private:
BHttpHeaders* fOptHeaders; BHttpHeaders* fOptHeaders;
BHttpForm* fOptPostFields; BHttpForm* fOptPostFields;
BDataIO* fOptInputData; BDataIO* fOptInputData;
ssize_t fOptInputDataSize;
bool fOptSetCookies : 1; bool fOptSetCookies : 1;
bool fOptFollowLocation : 1; bool fOptFollowLocation : 1;
bool fOptDiscardData : 1; bool fOptDiscardData : 1;
-136
View File
@@ -1,136 +0,0 @@
/*
* Copyright 2010 Haiku Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#ifndef _B_URL_PROTOCOL_H_
#define _B_URL_PROTOCOL_H_
#include <Url.h>
#include <UrlResult.h>
#include <UrlContext.h>
#include <UrlProtocolListener.h>
#include <OS.h>
class BUrlProtocol {
public:
BUrlProtocol(const BUrl& url,
BUrlProtocolListener* listener,
BUrlContext* context,
BUrlResult* result,
const char* threadName,
const char* protocolName);
virtual ~BUrlProtocol();
// URL protocol required members
// TODO: (stippi) I know it's sometimes appealing to have these
// "simplistic" methods that can do anything, but they remove
// type-safety. Why not overload SetOption with all possible types?
// Like:
// SetOption(uint32 option, bool value);
// SetOption(uint32 option, int8 value);
// SetOption(uint32 option, int16 value);
// SetOption(uint32 option, int32 value);
// ...
// This keeps the calling side even more simple, since it
// don't need to do pointer stuff with the parameters. Also, since
// this method is forced to be implemented in derived classes, why
// is it here at all? Why not have non-virtual setters for specific
// things, where the setter is properly named?
virtual status_t SetOption(uint32 name, void* value) = 0;
// URL protocol thread management
virtual thread_id Run();
virtual status_t Pause();
virtual status_t Resume();
virtual status_t Stop();
// URL protocol parameters modification
status_t SetUrl(const BUrl& url);
status_t SetResult(BUrlResult* result);
status_t SetContext(BUrlContext* context);
status_t SetListener(BUrlProtocolListener* listener);
// URL protocol parameters access
const BUrl& Url() const;
BUrlResult* Result() const;
BUrlContext* Context() const;
BUrlProtocolListener* Listener() const;
const BString& Protocol() const;
// URL protocol informations
bool IsRunning() const;
status_t Status() const;
virtual const char* StatusString(status_t threadStatus)
const;
protected:
static int32 _ThreadEntry(void* arg);
virtual status_t _ProtocolLoop();
virtual void _EmitDebug(BUrlProtocolDebugMessage type,
const char* format, ...);
// URL result parameters access
BMallocIO& _ResultRawData();
BHttpHeaders& _ResultHeaders();
void _SetResultStatusCode(int32 statusCode);
BString& _ResultStatusText();
protected:
BUrl fUrl;
BUrlResult* fResult;
BUrlContext* fContext;
BUrlProtocolListener* fListener;
bool fQuit;
bool fRunning;
status_t fThreadStatus;
thread_id fThreadId;
BString fThreadName;
BString fProtocol;
};
// TODO: Rename, this is in the global namespace.
enum {
B_PROT_THREAD_STATUS__BASE = 0,
B_PROT_SUCCESS = B_PROT_THREAD_STATUS__BASE,
B_PROT_RUNNING,
B_PROT_PAUSED,
B_PROT_ABORTED,
B_PROT_SOCKET_ERROR,
B_PROT_CONNECTION_FAILED,
B_PROT_CANT_RESOLVE_HOSTNAME,
B_PROT_WRITE_FAILED,
B_PROT_READ_FAILED,
B_PROT_NO_MEMORY,
B_PROT_PROTOCOL_ERROR,
// Thread status over this one are guaranteed to be
// errors
B_PROT_THREAD_STATUS__END
};
namespace BPrivate {
class BUrlProtocolOption {
public:
BUrlProtocolOption(void* value) : fValuePtr(value) { }
bool Bool() const { return *reinterpret_cast<bool*>(fValuePtr); }
int8 Int8() const { return *reinterpret_cast<int8*>(fValuePtr); }
int16 Int16() const { return *reinterpret_cast<int16*>(fValuePtr); }
int32 Int32() const { return *reinterpret_cast<int32*>(fValuePtr); }
char* String() const { return reinterpret_cast<char*>(fValuePtr); }
void* Pointer() const { return fValuePtr; }
private:
void* fValuePtr;
};
} // namespace BPrivate
#endif // _B_URL_PROTOCOL_H_
@@ -17,18 +17,18 @@ public:
bool transparent = false); bool transparent = false);
virtual ~BUrlProtocolAsynchronousListener(); virtual ~BUrlProtocolAsynchronousListener();
virtual void ConnectionOpened(BUrlProtocol* caller); virtual void ConnectionOpened(BUrlRequest* caller);
virtual void HostnameResolved(BUrlProtocol* caller, virtual void HostnameResolved(BUrlRequest* caller,
const char* ip); const char* ip);
virtual void ResponseStarted(BUrlProtocol* caller); virtual void ResponseStarted(BUrlRequest* caller);
virtual void HeadersReceived(BUrlProtocol* caller); virtual void HeadersReceived(BUrlRequest* caller);
virtual void DataReceived(BUrlProtocol* caller, virtual void DataReceived(BUrlRequest* caller,
const char* data, ssize_t size); const char* data, ssize_t size);
virtual void DownloadProgress(BUrlProtocol* caller, virtual void DownloadProgress(BUrlRequest* caller,
ssize_t bytesReceived, ssize_t bytesTotal); ssize_t bytesReceived, ssize_t bytesTotal);
virtual void UploadProgress(BUrlProtocol* caller, virtual void UploadProgress(BUrlRequest* caller,
ssize_t bytesSent, ssize_t bytesTotal); ssize_t bytesSent, ssize_t bytesTotal);
virtual void RequestCompleted(BUrlProtocol* caller, virtual void RequestCompleted(BUrlRequest* caller,
bool success); bool success);
// Synchronous listener access // Synchronous listener access
@@ -38,26 +38,23 @@ public:
const BMessenger& messenger); const BMessenger& messenger);
virtual ~BUrlProtocolDispatchingListener(); virtual ~BUrlProtocolDispatchingListener();
virtual void ConnectionOpened(BUrlProtocol* caller); virtual void ConnectionOpened(BUrlRequest* caller);
virtual void HostnameResolved(BUrlProtocol* caller, virtual void HostnameResolved(BUrlRequest* caller,
const char* ip); const char* ip);
virtual void ResponseStarted(BUrlProtocol* caller); virtual void ResponseStarted(BUrlRequest* caller);
virtual void HeadersReceived(BUrlProtocol* caller); virtual void HeadersReceived(BUrlRequest* caller);
virtual void DataReceived(BUrlProtocol* caller, virtual void DataReceived(BUrlRequest* caller,
const char* data, ssize_t size); const char* data, ssize_t size);
virtual void DownloadProgress(BUrlProtocol* caller, virtual void DownloadProgress(BUrlRequest* caller,
ssize_t bytesReceived, ssize_t bytesTotal); ssize_t bytesReceived, ssize_t bytesTotal);
virtual void UploadProgress(BUrlProtocol* caller, virtual void UploadProgress(BUrlRequest* caller,
ssize_t bytesSent, ssize_t bytesTotal); ssize_t bytesSent, ssize_t bytesTotal);
virtual void RequestCompleted(BUrlProtocol* caller, virtual void RequestCompleted(BUrlRequest* caller,
bool success); bool success);
virtual void DebugMessage(BUrlProtocol*,
BUrlProtocolDebugMessage,
const char*) { }
private: private:
void _SendMessage(BMessage* message, void _SendMessage(BMessage* message,
int8 notification, BUrlProtocol* caller); int8 notification, BUrlRequest* caller);
private: private:
BMessenger fMessenger; BMessenger fMessenger;
+19 -19
View File
@@ -9,7 +9,7 @@
#include <stddef.h> #include <stddef.h>
#include <cstdlib> #include <cstdlib>
class BUrlProtocol; class BUrlRequest;
enum BUrlProtocolDebugMessage { enum BUrlProtocolDebugMessage {
@@ -24,15 +24,15 @@ enum BUrlProtocolDebugMessage {
class BUrlProtocolListener { class BUrlProtocolListener {
public: public:
/* /**
ConnectionOpened() ConnectionOpened()
Frequency: Once Frequency: Once
Called when the socket is opened. Called when the socket is opened.
*/ */
virtual void ConnectionOpened(BUrlProtocol* caller); virtual void ConnectionOpened(BUrlRequest* caller);
/* /**
HostnameResolved(ip) HostnameResolved(ip)
Frequency: Once Frequency: Once
Parameters: ip String representing the IP address of the resource Parameters: ip String representing the IP address of the resource
@@ -40,28 +40,28 @@ public:
Called when the final IP is discovered Called when the final IP is discovered
*/ */
virtual void HostnameResolved(BUrlProtocol* caller, virtual void HostnameResolved(BUrlRequest* caller,
const char* ip); const char* ip);
/* /**
ReponseStarted() ReponseStarted()
Frequency: Once Frequency: Once
Called when the request has been emitted and the server begins to Called when the request has been emitted and the server begins to
reply. Typically when the HTTP status code is received. reply. Typically when the HTTP status code is received.
*/ */
virtual void ResponseStarted(BUrlProtocol* caller); virtual void ResponseStarted(BUrlRequest* caller);
/* /**
HeadersReceived() HeadersReceived()
Frequency: Once Frequency: Once
Called when all the server response metadata (such as headers) have Called when all the server response metadata (such as headers) have
been read and parsed. been read and parsed.
*/ */
virtual void HeadersReceived(BUrlProtocol* caller); virtual void HeadersReceived(BUrlRequest* caller);
/* /**
DataReceived(data, size) DataReceived(data, size)
Frequency: Zero or more Frequency: Zero or more
Parameters: data Pointer to the data block in memory Parameters: data Pointer to the data block in memory
@@ -69,10 +69,10 @@ public:
Called each time a full block of data is received. Called each time a full block of data is received.
*/ */
virtual void DataReceived(BUrlProtocol* caller, virtual void DataReceived(BUrlRequest* caller,
const char* data, ssize_t size); const char* data, ssize_t size);
/* /**
DownloadProgress(bytesReceived, bytesTotal) DownloadProgress(bytesReceived, bytesTotal)
Frequency: Once or more Frequency: Once or more
Parameters: bytesReceived Number of data bytes received Parameters: bytesReceived Number of data bytes received
@@ -80,10 +80,10 @@ public:
Called each time a data block is received. Called each time a data block is received.
*/ */
virtual void DownloadProgress(BUrlProtocol* caller, virtual void DownloadProgress(BUrlRequest* caller,
ssize_t bytesReceived, ssize_t bytesTotal); ssize_t bytesReceived, ssize_t bytesTotal);
/* /**
UploadProgress(bytesSent, bytesTotal) UploadProgress(bytesSent, bytesTotal)
Frequency: Once or more Frequency: Once or more
Parameters: bytesSent Number of data bytes sent Parameters: bytesSent Number of data bytes sent
@@ -91,10 +91,10 @@ public:
Called each time a data block is emitted. Called each time a data block is emitted.
*/ */
virtual void UploadProgress(BUrlProtocol* caller, virtual void UploadProgress(BUrlRequest* caller,
ssize_t bytesSent, ssize_t bytesTotal); ssize_t bytesSent, ssize_t bytesTotal);
/* /**
RequestCompleted(success) RequestCompleted(success)
Frequency: Once Frequency: Once
Parameters: success true if the resource have been successfully Parameters: success true if the resource have been successfully
@@ -102,17 +102,17 @@ public:
Called once the request is complete. Called once the request is complete.
*/ */
virtual void RequestCompleted(BUrlProtocol* caller, virtual void RequestCompleted(BUrlRequest* caller,
bool success); bool success);
/* /**
DebugMessage(type, text) DebugMessage(type, text)
Frequency: zero or more Frequency: zero or more
Parameters: type Type of the verbose message (see BUrlProtocolDebug) Parameters: type Type of the verbose message (see BUrlProtocolDebug)
Called each time a debug message is emitted Called each time a debug message is emitted
*/ */
virtual void DebugMessage(BUrlProtocol* caller, virtual void DebugMessage(BUrlRequest* caller,
BUrlProtocolDebugMessage type, BUrlProtocolDebugMessage type,
const char* text); const char* text);
}; };
+25
View File
@@ -0,0 +1,25 @@
/*
* Copyright 2013 Haiku Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#ifndef _B_URL_ROSTER_H_
#define _B_URL_ROSTER_H_
#include <stdlib.h>
class BUrl;
class BUrlContext;
class BUrlProtocolListener;
class BUrlRequest;
class BUrlProtocolRoster {
public:
static BUrlRequest* MakeRequest(const BUrl& url,
BUrlProtocolListener* listener = NULL,
BUrlContext* context = NULL);
};
#endif
+67 -38
View File
@@ -6,64 +6,93 @@
#define _B_URL_REQUEST_H_ #define _B_URL_REQUEST_H_
#include <HttpHeaders.h>
#include <Url.h> #include <Url.h>
#include <UrlResult.h> #include <UrlResult.h>
#include <UrlContext.h> #include <UrlContext.h>
#include <UrlProtocol.h>
#include <UrlProtocolListener.h> #include <UrlProtocolListener.h>
#include <OS.h>
enum {
B_NO_HANDLER_FOR_PROTOCOL = B_ERROR
};
class BUrlRequest { class BUrlRequest {
public: public:
BUrlRequest(const BUrl& url, BUrlRequest(const BUrl& url,
BUrlProtocolListener* listener = NULL, BUrlProtocolListener* listener,
BUrlContext* context = NULL); BUrlContext* context,
BUrlRequest(const BUrlRequest& other); BUrlResult& result,
const char* threadName,
const char* protocolName);
virtual ~BUrlRequest(); virtual ~BUrlRequest();
// Request parameters modification // URL protocol thread management
status_t SetUrl(const BUrl& url); virtual thread_id Run();
void SetContext(BUrlContext* context);
void SetProtocolListener(
BUrlProtocolListener* listener);
bool SetProtocolOption(int32 option,
void* value);
// Request parameters access
const BUrlProtocol* Protocol();
const BUrlResult& Result();
const BUrl& Url();
// Request control
virtual status_t Start();
virtual status_t Pause(); virtual status_t Pause();
virtual status_t Resume(); virtual status_t Resume();
virtual status_t Abort(); virtual status_t Stop();
// Request informations // URL protocol parameters modification
virtual status_t InitCheck() const; status_t SetUrl(const BUrl& url);
status_t SetResult(BUrlResult& result);
status_t SetContext(BUrlContext* context);
status_t SetListener(BUrlProtocolListener* listener);
// URL protocol parameters access
const BUrl& Url() const;
BUrlResult& Result() const;
BUrlContext* Context() const;
BUrlProtocolListener* Listener() const;
const BString& Protocol() const;
// URL protocol informations
bool IsRunning() const; bool IsRunning() const;
status_t Status() const; status_t Status() const;
virtual const char* StatusString(status_t threadStatus)
// Overloaded members const;
BUrlRequest& operator=(const BUrlRequest& other);
protected: protected:
BUrlProtocolListener* fListener; static int32 _ThreadEntry(void* arg);
BUrlProtocol* fUrlProtocol; virtual status_t _ProtocolLoop();
BUrlResult fResult; virtual void _EmitDebug(BUrlProtocolDebugMessage type,
BUrlContext* fContext; const char* format, ...);
BUrl fUrl;
status_t fInitStatus;
private: // URL result parameters access
status_t _SetupProtocol(); BMallocIO& _ResultRawData();
BHttpHeaders& _ResultHeaders();
void _SetResultStatusCode(int32 statusCode);
BString& _ResultStatusText();
protected:
BUrl fUrl;
BUrlResult& fResult;
BUrlContext* fContext;
BUrlProtocolListener* fListener;
bool fQuit;
bool fRunning;
status_t fThreadStatus;
thread_id fThreadId;
BString fThreadName;
BString fProtocol;
};
// TODO: Rename, this is in the global namespace.
enum {
B_PROT_THREAD_STATUS__BASE = 0,
B_PROT_SUCCESS = B_PROT_THREAD_STATUS__BASE,
B_PROT_RUNNING,
B_PROT_PAUSED,
B_PROT_ABORTED,
B_PROT_SOCKET_ERROR,
B_PROT_CONNECTION_FAILED,
B_PROT_CANT_RESOLVE_HOSTNAME,
B_PROT_WRITE_FAILED,
B_PROT_READ_FAILED,
B_PROT_NO_MEMORY,
B_PROT_PROTOCOL_ERROR,
// Thread status over this one are guaranteed to be
// errors
B_PROT_THREAD_STATUS__END
}; };
#endif // _B_URL_REQUEST_H_ #endif // _B_URL_REQUEST_H_
+2 -2
View File
@@ -14,11 +14,11 @@
#include <Url.h> #include <Url.h>
class BUrlProtocol; class BUrlRequest;
class BUrlResult { class BUrlResult {
friend class BUrlProtocol; friend class BUrlRequest;
public: public:
BUrlResult(const BUrl& url); BUrlResult(const BUrl& url);
+10 -9
View File
@@ -12,7 +12,7 @@
class BUrlSynchronousRequest : public BUrlRequest, public BUrlProtocolListener { class BUrlSynchronousRequest : public BUrlRequest, public BUrlProtocolListener {
public: public:
BUrlSynchronousRequest(BUrl& url); BUrlSynchronousRequest(BUrlRequest& asynchronousRequest);
virtual ~BUrlSynchronousRequest() { }; virtual ~BUrlSynchronousRequest() { };
// Synchronous wait // Synchronous wait
@@ -20,23 +20,24 @@ public:
virtual status_t WaitUntilCompletion(); virtual status_t WaitUntilCompletion();
// Protocol hooks // Protocol hooks
virtual void ConnectionOpened(BUrlProtocol* caller); virtual void ConnectionOpened(BUrlRequest* caller);
virtual void HostnameResolved(BUrlProtocol* caller, virtual void HostnameResolved(BUrlRequest* caller,
const char* ip); const char* ip);
virtual void ResponseStarted(BUrlProtocol* caller); virtual void ResponseStarted(BUrlRequest* caller);
virtual void HeadersReceived(BUrlProtocol* caller); virtual void HeadersReceived(BUrlRequest* caller);
virtual void DataReceived(BUrlProtocol* caller, virtual void DataReceived(BUrlRequest* caller,
const char* data, ssize_t size); const char* data, ssize_t size);
virtual void DownloadProgress(BUrlProtocol* caller, virtual void DownloadProgress(BUrlRequest* caller,
ssize_t bytesReceived, ssize_t bytesTotal); ssize_t bytesReceived, ssize_t bytesTotal);
virtual void UploadProgress(BUrlProtocol* caller, virtual void UploadProgress(BUrlRequest* caller,
ssize_t bytesSent, ssize_t bytesTotal); ssize_t bytesSent, ssize_t bytesTotal);
virtual void RequestCompleted(BUrlProtocol* caller, virtual void RequestCompleted(BUrlRequest* caller,
bool success); bool success);
protected: protected:
bool fRequestComplete; bool fRequestComplete;
BUrlRequest& fWrappedRequest;
}; };
-7
View File
@@ -184,13 +184,6 @@ BHttpFormData::MarkAsFile(const BString& filename, const BString& mimeType)
} }
status_t
BHttpFormData::MarkAsFile(const BString& filename)
{
return MarkAsFile(filename, "");
}
void void
BHttpFormData::UnmarkAsFile() BHttpFormData::UnmarkAsFile()
{ {
@@ -277,6 +277,8 @@ BHttpHeaders::Clear()
BHttpHeaders& BHttpHeaders&
BHttpHeaders::operator=(const BHttpHeaders& other) BHttpHeaders::operator=(const BHttpHeaders& other)
{ {
Clear();
for (int32 i = 0; i < other.CountHeaders(); i++) for (int32 i = 0; i < other.CountHeaders(); i++)
AddHeader(other.HeaderAt(i).Name(), other.HeaderAt(i).Value()); AddHeader(other.HeaderAt(i).Name(), other.HeaderAt(i).Value());
@@ -17,10 +17,7 @@
#include <File.h> #include <File.h>
#include <Socket.h> #include <Socket.h>
#include <SecureSocket.h> #include <SecureSocket.h>
#include <UrlProtocolHttp.h> #include <HttpRequest.h>
using BPrivate::BUrlProtocolOption;
static const int32 kHttpProtocolReceiveBufferSize = 1024; static const int32 kHttpProtocolReceiveBufferSize = 1024;
@@ -31,11 +28,11 @@ static const char* kHttpProtocolThreadStrStatus[
}; };
BUrlProtocolHttp::BUrlProtocolHttp(BUrl& url, bool ssl, BHttpRequest::BHttpRequest(const BUrl& url, BUrlResult& result, bool ssl,
const char* protocolName, BUrlProtocolListener* listener, const char* protocolName, BUrlProtocolListener* listener,
BUrlContext* context, BUrlResult* result) BUrlContext* context)
: :
BUrlProtocol(url, listener, context, result, "BUrlProtocol.HTTP", protocolName), BUrlRequest(url, listener, context, result, "BUrlProtocol.HTTP", protocolName),
fSSL(ssl), fSSL(ssl),
fRequestMethod(B_HTTP_GET), fRequestMethod(B_HTTP_GET),
fHttpVersion(B_HTTP_11) fHttpVersion(B_HTTP_11)
@@ -48,83 +45,109 @@ BUrlProtocolHttp::BUrlProtocolHttp(BUrl& url, bool ssl,
} }
BUrlProtocolHttp::~BUrlProtocolHttp() BHttpRequest::~BHttpRequest()
{ {
delete fSocket; delete fSocket;
} }
status_t void
BUrlProtocolHttp::SetOption(uint32 name, void* value) BHttpRequest::SetMethod(int8 method)
{ {
BUrlProtocolOption option(value); fRequestMethod = method;
}
switch (name) {
case B_HTTPOPT_METHOD:
fRequestMethod = option.Int8();
break;
case B_HTTPOPT_FOLLOWLOCATION: void
fOptFollowLocation = option.Bool(); BHttpRequest::SetFollowLocation(bool follow)
break; {
fOptFollowLocation = follow;
}
case B_HTTPOPT_MAXREDIRS:
fOptMaxRedirs = option.Int8();
break;
case B_HTTPOPT_REFERER: void
fOptReferer = option.String(); BHttpRequest::SetMaxRedirections(int8 redirections)
break; {
fOptMaxRedirs = redirections;
}
case B_HTTPOPT_USERAGENT:
fOptUserAgent = option.String();
break;
case B_HTTPOPT_HEADERS: void
fOptHeaders = reinterpret_cast<BHttpHeaders*>(option.Pointer()); BHttpRequest::SetReferrer(const BString& referrer)
break; {
fOptReferer = referrer;
}
case B_HTTPOPT_DISCARD_DATA:
fOptDiscardData = option.Bool();
break;
case B_HTTPOPT_DISABLE_LISTENER: void
fOptDisableListener = option.Bool(); BHttpRequest::SetUserAgent(const BString& agent)
break; {
fOptUserAgent = agent;
}
case B_HTTPOPT_AUTOREFERER:
fOptAutoReferer = option.Bool();
break;
case B_HTTPOPT_POSTFIELDS: void
fOptPostFields = reinterpret_cast<BHttpForm*>(option.Pointer()); BHttpRequest::SetHeaders(BHttpHeaders* headers)
{
fOptHeaders = headers;
}
if (fOptPostFields != NULL)
fRequestMethod = B_HTTP_POST;
break;
case B_HTTPOPT_INPUTDATA: void
fOptInputData = reinterpret_cast<BDataIO*>(option.Pointer()); BHttpRequest::SetDiscardData(bool discard)
break; {
fOptDiscardData = discard;
}
case B_HTTPOPT_AUTHUSERNAME:
fOptUsername = option.String();
break;
case B_HTTPOPT_AUTHPASSWORD: void
fOptPassword = option.String(); BHttpRequest::SetDisableListener(bool disable)
break; {
fOptDisableListener = disable;
}
default:
return B_ERROR;
}
return B_OK; void
BHttpRequest::SetAutoReferrer(bool enable)
{
fOptAutoReferer = enable;
}
void
BHttpRequest::SetPostFields(BHttpForm* fields)
{
fOptPostFields = fields;
if (fOptPostFields != NULL)
fRequestMethod = B_HTTP_POST;
}
void
BHttpRequest::SetInputData(BDataIO* data, ssize_t size)
{
fOptInputData = data;
fOptInputDataSize = size;
}
void
BHttpRequest::SetUserName(const BString& name)
{
fOptUsername = name;
}
void
BHttpRequest::SetPassword(const BString& password)
{
fOptPassword = password;
} }
/*static*/ bool /*static*/ bool
BUrlProtocolHttp::IsInformationalStatusCode(int16 code) BHttpRequest::IsInformationalStatusCode(int16 code)
{ {
return (code >= B_HTTP_STATUS__INFORMATIONAL_BASE) return (code >= B_HTTP_STATUS__INFORMATIONAL_BASE)
&& (code < B_HTTP_STATUS__INFORMATIONAL_END); && (code < B_HTTP_STATUS__INFORMATIONAL_END);
@@ -132,7 +155,7 @@ BUrlProtocolHttp::IsInformationalStatusCode(int16 code)
/*static*/ bool /*static*/ bool
BUrlProtocolHttp::IsSuccessStatusCode(int16 code) BHttpRequest::IsSuccessStatusCode(int16 code)
{ {
return (code >= B_HTTP_STATUS__SUCCESS_BASE) return (code >= B_HTTP_STATUS__SUCCESS_BASE)
&& (code < B_HTTP_STATUS__SUCCESS_END); && (code < B_HTTP_STATUS__SUCCESS_END);
@@ -140,7 +163,7 @@ BUrlProtocolHttp::IsSuccessStatusCode(int16 code)
/*static*/ bool /*static*/ bool
BUrlProtocolHttp::IsRedirectionStatusCode(int16 code) BHttpRequest::IsRedirectionStatusCode(int16 code)
{ {
return (code >= B_HTTP_STATUS__REDIRECTION_BASE) return (code >= B_HTTP_STATUS__REDIRECTION_BASE)
&& (code < B_HTTP_STATUS__REDIRECTION_END); && (code < B_HTTP_STATUS__REDIRECTION_END);
@@ -148,7 +171,7 @@ BUrlProtocolHttp::IsRedirectionStatusCode(int16 code)
/*static*/ bool /*static*/ bool
BUrlProtocolHttp::IsClientErrorStatusCode(int16 code) BHttpRequest::IsClientErrorStatusCode(int16 code)
{ {
return (code >= B_HTTP_STATUS__CLIENT_ERROR_BASE) return (code >= B_HTTP_STATUS__CLIENT_ERROR_BASE)
&& (code < B_HTTP_STATUS__CLIENT_ERROR_END); && (code < B_HTTP_STATUS__CLIENT_ERROR_END);
@@ -156,7 +179,7 @@ BUrlProtocolHttp::IsClientErrorStatusCode(int16 code)
/*static*/ bool /*static*/ bool
BUrlProtocolHttp::IsServerErrorStatusCode(int16 code) BHttpRequest::IsServerErrorStatusCode(int16 code)
{ {
return (code >= B_HTTP_STATUS__SERVER_ERROR_BASE) return (code >= B_HTTP_STATUS__SERVER_ERROR_BASE)
&& (code < B_HTTP_STATUS__SERVER_ERROR_END); && (code < B_HTTP_STATUS__SERVER_ERROR_END);
@@ -164,17 +187,17 @@ BUrlProtocolHttp::IsServerErrorStatusCode(int16 code)
/*static*/ int16 /*static*/ int16
BUrlProtocolHttp::StatusCodeClass(int16 code) BHttpRequest::StatusCodeClass(int16 code)
{ {
if (BUrlProtocolHttp::IsInformationalStatusCode(code)) if (BHttpRequest::IsInformationalStatusCode(code))
return B_HTTP_STATUS_CLASS_INFORMATIONAL; return B_HTTP_STATUS_CLASS_INFORMATIONAL;
else if (BUrlProtocolHttp::IsSuccessStatusCode(code)) else if (BHttpRequest::IsSuccessStatusCode(code))
return B_HTTP_STATUS_CLASS_SUCCESS; return B_HTTP_STATUS_CLASS_SUCCESS;
else if (BUrlProtocolHttp::IsRedirectionStatusCode(code)) else if (BHttpRequest::IsRedirectionStatusCode(code))
return B_HTTP_STATUS_CLASS_REDIRECTION; return B_HTTP_STATUS_CLASS_REDIRECTION;
else if (BUrlProtocolHttp::IsClientErrorStatusCode(code)) else if (BHttpRequest::IsClientErrorStatusCode(code))
return B_HTTP_STATUS_CLASS_CLIENT_ERROR; return B_HTTP_STATUS_CLASS_CLIENT_ERROR;
else if (BUrlProtocolHttp::IsServerErrorStatusCode(code)) else if (BHttpRequest::IsServerErrorStatusCode(code))
return B_HTTP_STATUS_CLASS_SERVER_ERROR; return B_HTTP_STATUS_CLASS_SERVER_ERROR;
return B_HTTP_STATUS_CLASS_INVALID; return B_HTTP_STATUS_CLASS_INVALID;
@@ -182,12 +205,12 @@ BUrlProtocolHttp::StatusCodeClass(int16 code)
const char* const char*
BUrlProtocolHttp::StatusString(status_t threadStatus) const BHttpRequest::StatusString(status_t threadStatus) const
{ {
if (threadStatus < B_PROT_THREAD_STATUS__END) if (threadStatus < B_PROT_THREAD_STATUS__END)
return BUrlProtocol::StatusString(threadStatus); return BUrlRequest::StatusString(threadStatus);
else if (threadStatus >= B_PROT_HTTP_THREAD_STATUS__END) else if (threadStatus >= B_PROT_HTTP_THREAD_STATUS__END)
return BUrlProtocol::StatusString(-1); return BUrlRequest::StatusString(-1);
else else
return kHttpProtocolThreadStrStatus[threadStatus return kHttpProtocolThreadStrStatus[threadStatus
- B_PROT_THREAD_STATUS__END]; - B_PROT_THREAD_STATUS__END];
@@ -195,7 +218,7 @@ BUrlProtocolHttp::StatusString(status_t threadStatus) const
void void
BUrlProtocolHttp::_ResetOptions() BHttpRequest::_ResetOptions()
{ {
fOptFollowLocation = true; fOptFollowLocation = true;
fOptMaxRedirs = 8; fOptMaxRedirs = 8;
@@ -215,7 +238,7 @@ BUrlProtocolHttp::_ResetOptions()
#include <stdio.h> #include <stdio.h>
status_t status_t
BUrlProtocolHttp::_ProtocolLoop() BHttpRequest::_ProtocolLoop()
{ {
printf("UHP[%p]::{Loop} %s\n", this, fUrl.UrlString().String()); printf("UHP[%p]::{Loop} %s\n", this, fUrl.UrlString().String());
@@ -252,7 +275,7 @@ BUrlProtocolHttp::_ProtocolLoop()
if (fOptAutoReferer) if (fOptAutoReferer)
fOptReferer = fUrl.UrlString(); fOptReferer = fUrl.UrlString();
switch (StatusCodeClass(fResult->StatusCode())) { switch (StatusCodeClass(fResult.StatusCode())) {
case B_HTTP_STATUS_CLASS_INFORMATIONAL: case B_HTTP_STATUS_CLASS_INFORMATIONAL:
// Header 100:continue should have been // Header 100:continue should have been
// handled in the _MakeRequest read loop // handled in the _MakeRequest read loop
@@ -268,7 +291,7 @@ BUrlProtocolHttp::_ProtocolLoop()
// TODO: Some browsers seems to translate POST requests to // TODO: Some browsers seems to translate POST requests to
// GET when following a 302 redirection // GET when following a 302 redirection
if (fResult->StatusCode() == B_HTTP_STATUS_MOVED_PERMANENTLY) { if (fResult.StatusCode() == B_HTTP_STATUS_MOVED_PERMANENTLY) {
BString locationUrl = fHeaders["Location"]; BString locationUrl = fHeaders["Location"];
// Absolute path // Absolute path
@@ -289,7 +312,7 @@ BUrlProtocolHttp::_ProtocolLoop()
break; break;
case B_HTTP_STATUS_CLASS_CLIENT_ERROR: case B_HTTP_STATUS_CLASS_CLIENT_ERROR:
switch (fResult->StatusCode()) { switch (fResult.StatusCode()) {
case B_HTTP_STATUS_UNAUTHORIZED: case B_HTTP_STATUS_UNAUTHORIZED:
if (fAuthentication.Method() != B_HTTP_AUTHENTICATION_NONE) { if (fAuthentication.Method() != B_HTTP_AUTHENTICATION_NONE) {
newRequest = false; newRequest = false;
@@ -321,7 +344,7 @@ BUrlProtocolHttp::_ProtocolLoop()
"%ld headers and %ld bytes of data remaining", "%ld headers and %ld bytes of data remaining",
fHeaders.CountHeaders(), fInputBuffer.Size()); fHeaders.CountHeaders(), fInputBuffer.Size());
if (fResult->StatusCode() == 404) if (fResult.StatusCode() == 404)
return B_PROT_HTTP_NOT_FOUND; return B_PROT_HTTP_NOT_FOUND;
return B_PROT_SUCCESS; return B_PROT_SUCCESS;
@@ -329,7 +352,7 @@ BUrlProtocolHttp::_ProtocolLoop()
bool bool
BUrlProtocolHttp::_ResolveHostName() BHttpRequest::_ResolveHostName()
{ {
_EmitDebug(B_URL_PROTOCOL_DEBUG_TEXT, "Resolving %s", _EmitDebug(B_URL_PROTOCOL_DEBUG_TEXT, "Resolving %s",
fUrl.UrlString().String()); fUrl.UrlString().String());
@@ -357,7 +380,7 @@ BUrlProtocolHttp::_ResolveHostName()
status_t status_t
BUrlProtocolHttp::_MakeRequest() BHttpRequest::_MakeRequest()
{ {
_EmitDebug(B_URL_PROTOCOL_DEBUG_TEXT, "Connection to %s on port %d.", _EmitDebug(B_URL_PROTOCOL_DEBUG_TEXT, "Connection to %s on port %d.",
fUrl.Authority().String(), fRemoteAddr.Port()); fUrl.Authority().String(), fRemoteAddr.Port());
@@ -442,13 +465,19 @@ BUrlProtocolHttp::_MakeRequest()
read = fOptInputData->Read(outputTempBuffer, 1024); read = fOptInputData->Read(outputTempBuffer, 1024);
if (read > 0) { if (read > 0) {
char hexSize[16]; if (fOptInputDataSize < 0)
size_t hexLength = sprintf(hexSize, "%ld", read); {
// Chunked transfer
char hexSize[16];
size_t hexLength = sprintf(hexSize, "%ld", read);
fSocket->Write(hexSize, hexLength); fSocket->Write(hexSize, hexLength);
fSocket->Write("\r\n", 2); fSocket->Write("\r\n", 2);
fSocket->Write(outputTempBuffer, read); fSocket->Write(outputTempBuffer, read);
fSocket->Write("\r\n", 2); fSocket->Write("\r\n", 2);
} else {
fSocket->Write(outputTempBuffer, read);
}
} }
} }
@@ -626,7 +655,7 @@ BUrlProtocolHttp::_MakeRequest()
status_t status_t
BUrlProtocolHttp::_GetLine(BString& destString) BHttpRequest::_GetLine(BString& destString)
{ {
// Find a complete line in inputBuffer // Find a complete line in inputBuffer
uint32 characterIndex = 0; uint32 characterIndex = 0;
@@ -653,7 +682,7 @@ BUrlProtocolHttp::_GetLine(BString& destString)
void void
BUrlProtocolHttp::_ParseStatus() BHttpRequest::_ParseStatus()
{ {
// Status line should be formatted like: HTTP/M.m SSS ... // Status line should be formatted like: HTTP/M.m SSS ...
// With: M = Major version of the protocol // With: M = Major version of the protocol
@@ -682,7 +711,7 @@ BUrlProtocolHttp::_ParseStatus()
void void
BUrlProtocolHttp::_ParseHeaders() BHttpRequest::_ParseHeaders()
{ {
BString currentHeader; BString currentHeader;
if (_GetLine(currentHeader) == B_ERROR) if (_GetLine(currentHeader) == B_ERROR)
@@ -700,7 +729,7 @@ BUrlProtocolHttp::_ParseHeaders()
void void
BUrlProtocolHttp::_CreateRequest() BHttpRequest::_CreateRequest()
{ {
BString request; BString request;
@@ -748,7 +777,7 @@ BUrlProtocolHttp::_CreateRequest()
void void
BUrlProtocolHttp::_AddHeaders() BHttpRequest::_AddHeaders()
{ {
// HTTP 1.1 additional headers // HTTP 1.1 additional headers
if (fHttpVersion == B_HTTP_11) { if (fHttpVersion == B_HTTP_11) {
@@ -813,8 +842,14 @@ BUrlProtocolHttp::_AddHeaders()
fOutputHeaders.AddHeader("Content-Length", fOutputHeaders.AddHeader("Content-Length",
fOptPostFields->ContentLength()); fOptPostFields->ContentLength());
} else if (fOptInputData != NULL } else if (fOptInputData != NULL
&& (fRequestMethod == B_HTTP_POST || fRequestMethod == B_HTTP_PUT)) && (fRequestMethod == B_HTTP_POST || fRequestMethod == B_HTTP_PUT))
fOutputHeaders.AddHeader("Transfer-Encoding", "chunked"); {
if(fOptInputDataSize >= 0) {
fOutputHeaders.AddHeader("Content-Length", fOptInputDataSize);
} else {
fOutputHeaders.AddHeader("Transfer-Encoding", "chunked");
}
}
// Optional headers specified by the user // Optional headers specified by the user
if (fOptHeaders != NULL) { if (fOptHeaders != NULL) {
@@ -850,7 +885,7 @@ BUrlProtocolHttp::_AddHeaders()
void void
BUrlProtocolHttp::_AddOutputBufferLine(const char* line) BHttpRequest::_AddOutputBufferLine(const char* line)
{ {
_EmitDebug(B_URL_PROTOCOL_DEBUG_HEADER_OUT, "%s", line); _EmitDebug(B_URL_PROTOCOL_DEBUG_HEADER_OUT, "%s", line);
fOutputBuffer << line << "\r\n"; fOutputBuffer << line << "\r\n";
+2 -5
View File
@@ -54,23 +54,20 @@ for architectureObject in [ MultiArchSubDirSetup ] {
# TODO: The HTTP stuff should all go into an add-on. It needs # TODO: The HTTP stuff should all go into an add-on. It needs
# linking against libcrypto.so and only the add-on should link # linking against libcrypto.so and only the add-on should link
# against it. # against it.
# Building of the commented out files has not been completely tested
# after integrating the code from the GSoC 2010 "Services Kit"
# project and doing some renaming of types, constants and methods.
HttpAuthentication.cpp HttpAuthentication.cpp
HttpHeaders.cpp HttpHeaders.cpp
HttpForm.cpp HttpForm.cpp
HttpRequest.cpp
HttpTime.cpp HttpTime.cpp
$(md5Sources) $(md5Sources)
Url.cpp Url.cpp
UrlContext.cpp UrlContext.cpp
UrlProtocol.cpp
UrlProtocolAsynchronousListener.cpp UrlProtocolAsynchronousListener.cpp
UrlProtocolDispatchingListener.cpp UrlProtocolDispatchingListener.cpp
UrlProtocolHttp.cpp # TODO: -> add-on, See above.
UrlProtocolListener.cpp UrlProtocolListener.cpp
UrlProtocolRoster.cpp
UrlRequest.cpp UrlRequest.cpp
UrlResult.cpp UrlResult.cpp
UrlSynchronousRequest.cpp UrlSynchronousRequest.cpp
-303
View File
@@ -1,303 +0,0 @@
/*
* Copyright 2010 Haiku Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Christophe Huriaux, [email protected]
*/
#include <UrlProtocol.h>
#include <Debug.h>
#include <stdio.h>
static const char* kProtocolThreadStrStatus[B_PROT_THREAD_STATUS__END+1]
= {
"Request successfully completed",
"Request running",
"Socket error",
"Connection failed",
"Hostname resolution failed",
"Network write failed",
"Network read failed",
"Out of memory",
"Protocol-specific error",
"Unknown error"
};
BUrlProtocol::BUrlProtocol(const BUrl& url, BUrlProtocolListener* listener,
BUrlContext* context, BUrlResult* result, const char* threadName,
const char* protocolName)
:
fUrl(url),
fResult(result),
fContext(context),
fListener(listener),
fQuit(false),
fRunning(false),
fThreadId(0),
fThreadName(threadName),
fProtocol(protocolName)
{
}
BUrlProtocol::~BUrlProtocol()
{
}
// #pragma mark URL protocol thread management
thread_id
BUrlProtocol::Run()
{
// Thread already running
if (fRunning) {
PRINT(("BUrlProtocol::Run() : Oops, already running ! "
"[urlProtocol=%p]!\n", this));
return fThreadId;
}
fThreadId = spawn_thread(BUrlProtocol::_ThreadEntry, fThreadName,
B_NORMAL_PRIORITY, this);
if (fThreadId < B_OK)
return fThreadId;
status_t launchErr = resume_thread(fThreadId);
if (launchErr < B_OK) {
PRINT(("BUrlProtocol::Run() : Failed to resume thread %ld\n",
fThreadId));
return launchErr;
}
fRunning = true;
return fThreadId;
}
status_t
BUrlProtocol::Pause()
{
// TODO
return B_ERROR;
}
status_t
BUrlProtocol::Resume()
{
// TODO
return B_ERROR;
}
status_t
BUrlProtocol::Stop()
{
if (!fRunning)
return B_ERROR;
status_t threadStatus = B_OK;
fQuit = true;
wait_for_thread(fThreadId, &threadStatus);
return threadStatus;
}
// #pragma mark URL protocol parameters modification
status_t
BUrlProtocol::SetUrl(const BUrl& url)
{
// We should avoid to change URL while the thread is running ...
if (IsRunning())
return B_ERROR;
fUrl = url;
return B_OK;
}
status_t
BUrlProtocol::SetResult(BUrlResult* result)
{
if (IsRunning())
return B_ERROR;
fResult = result;
return B_OK;
}
status_t
BUrlProtocol::SetContext(BUrlContext* context)
{
if (IsRunning())
return B_ERROR;
fContext = context;
return B_OK;
}
status_t
BUrlProtocol::SetListener(BUrlProtocolListener* listener)
{
if (IsRunning())
return B_ERROR;
fListener = listener;
return B_OK;
}
// #pragma mark URL protocol parameters access
const BUrl&
BUrlProtocol::Url() const
{
return fUrl;
}
BUrlResult*
BUrlProtocol::Result() const
{
return fResult;
}
BUrlContext*
BUrlProtocol::Context() const
{
return fContext;
}
BUrlProtocolListener*
BUrlProtocol::Listener() const
{
return fListener;
}
const BString&
BUrlProtocol::Protocol() const
{
return fProtocol;
}
// #pragma mark URL protocol informations
bool
BUrlProtocol::IsRunning() const
{
return fRunning;
}
status_t
BUrlProtocol::Status() const
{
return fThreadStatus;
}
const char*
BUrlProtocol::StatusString(status_t threadStatus) const
{
if (threadStatus < B_PROT_THREAD_STATUS__BASE)
threadStatus = B_PROT_THREAD_STATUS__END;
else if (threadStatus >= B_PROT_PROTOCOL_ERROR)
threadStatus = B_PROT_PROTOCOL_ERROR;
return kProtocolThreadStrStatus[threadStatus];
}
// #pragma mark Thread management
/*static*/ int32
BUrlProtocol::_ThreadEntry(void* arg)
{
BUrlProtocol* urlProtocol = reinterpret_cast<BUrlProtocol*>(arg);
urlProtocol->fThreadStatus = B_PROT_RUNNING;
status_t protocolLoopExitStatus = urlProtocol->_ProtocolLoop();
urlProtocol->fRunning = false;
urlProtocol->fThreadStatus = protocolLoopExitStatus;
if (urlProtocol->fListener != NULL)
urlProtocol->fListener->RequestCompleted(urlProtocol,
protocolLoopExitStatus == B_PROT_SUCCESS);
return B_OK;
}
status_t
BUrlProtocol::_ProtocolLoop()
{
// Dummy _ProtocolLoop
while (!fQuit)
snooze(1000);
return B_PROT_SUCCESS;
}
void
BUrlProtocol::_EmitDebug(BUrlProtocolDebugMessage type,
const char* format, ...)
{
if (fListener == NULL)
return;
va_list arguments;
va_start(arguments, format);
char debugMsg[256];
vsnprintf(debugMsg, 256, format, arguments);
fListener->DebugMessage(this, type, debugMsg);
va_end(arguments);
}
BMallocIO&
BUrlProtocol::_ResultRawData()
{
return fResult->fRawData;
}
BHttpHeaders&
BUrlProtocol::_ResultHeaders()
{
return fResult->fHeaders;
}
void
BUrlProtocol::_SetResultStatusCode(int32 statusCode)
{
fResult->fStatusCode = statusCode;
}
BString&
BUrlProtocol::_ResultStatusText()
{
return fResult->fStatusString;
}
@@ -46,52 +46,52 @@ BUrlProtocolAsynchronousListener::~BUrlProtocolAsynchronousListener()
void void
BUrlProtocolAsynchronousListener::ConnectionOpened(BUrlProtocol*) BUrlProtocolAsynchronousListener::ConnectionOpened(BUrlRequest*)
{ {
} }
void void
BUrlProtocolAsynchronousListener::HostnameResolved(BUrlProtocol*, const char*) BUrlProtocolAsynchronousListener::HostnameResolved(BUrlRequest*, const char*)
{ {
} }
void void
BUrlProtocolAsynchronousListener::ResponseStarted(BUrlProtocol*) BUrlProtocolAsynchronousListener::ResponseStarted(BUrlRequest*)
{ {
} }
void void
BUrlProtocolAsynchronousListener::HeadersReceived(BUrlProtocol*) BUrlProtocolAsynchronousListener::HeadersReceived(BUrlRequest*)
{ {
} }
void void
BUrlProtocolAsynchronousListener::DataReceived(BUrlProtocol*, const char*, BUrlProtocolAsynchronousListener::DataReceived(BUrlRequest*, const char*,
ssize_t) ssize_t)
{ {
} }
void void
BUrlProtocolAsynchronousListener::DownloadProgress(BUrlProtocol*, ssize_t, BUrlProtocolAsynchronousListener::DownloadProgress(BUrlRequest*, ssize_t,
ssize_t) ssize_t)
{ {
} }
void void
BUrlProtocolAsynchronousListener::UploadProgress(BUrlProtocol*, ssize_t, BUrlProtocolAsynchronousListener::UploadProgress(BUrlRequest*, ssize_t,
ssize_t) ssize_t)
{ {
} }
void void
BUrlProtocolAsynchronousListener::RequestCompleted(BUrlProtocol*, bool) BUrlProtocolAsynchronousListener::RequestCompleted(BUrlRequest*, bool)
{ {
} }
@@ -114,7 +114,7 @@ BUrlProtocolAsynchronousListener::MessageReceived(BMessage* message)
return; return;
} }
BUrlProtocol* caller; BUrlRequest* caller;
if (message->FindPointer(kUrlProtocolCaller, if (message->FindPointer(kUrlProtocolCaller,
reinterpret_cast<void**>(&caller)) != B_OK) reinterpret_cast<void**>(&caller)) != B_OK)
return; return;
@@ -37,7 +37,7 @@ BUrlProtocolDispatchingListener::~BUrlProtocolDispatchingListener()
void void
BUrlProtocolDispatchingListener::ConnectionOpened(BUrlProtocol* caller) BUrlProtocolDispatchingListener::ConnectionOpened(BUrlRequest* caller)
{ {
BMessage message(B_URL_PROTOCOL_NOTIFICATION); BMessage message(B_URL_PROTOCOL_NOTIFICATION);
_SendMessage(&message, B_URL_PROTOCOL_CONNECTION_OPENED, caller); _SendMessage(&message, B_URL_PROTOCOL_CONNECTION_OPENED, caller);
@@ -45,7 +45,7 @@ BUrlProtocolDispatchingListener::ConnectionOpened(BUrlProtocol* caller)
void void
BUrlProtocolDispatchingListener::HostnameResolved(BUrlProtocol* caller, BUrlProtocolDispatchingListener::HostnameResolved(BUrlRequest* caller,
const char* ip) const char* ip)
{ {
BMessage message(B_URL_PROTOCOL_NOTIFICATION); BMessage message(B_URL_PROTOCOL_NOTIFICATION);
@@ -56,7 +56,7 @@ BUrlProtocolDispatchingListener::HostnameResolved(BUrlProtocol* caller,
void void
BUrlProtocolDispatchingListener::ResponseStarted(BUrlProtocol* caller) BUrlProtocolDispatchingListener::ResponseStarted(BUrlRequest* caller)
{ {
BMessage message(B_URL_PROTOCOL_NOTIFICATION); BMessage message(B_URL_PROTOCOL_NOTIFICATION);
_SendMessage(&message, B_URL_PROTOCOL_RESPONSE_STARTED, caller); _SendMessage(&message, B_URL_PROTOCOL_RESPONSE_STARTED, caller);
@@ -64,7 +64,7 @@ BUrlProtocolDispatchingListener::ResponseStarted(BUrlProtocol* caller)
void void
BUrlProtocolDispatchingListener::HeadersReceived(BUrlProtocol* caller) BUrlProtocolDispatchingListener::HeadersReceived(BUrlRequest* caller)
{ {
BMessage message(B_URL_PROTOCOL_NOTIFICATION); BMessage message(B_URL_PROTOCOL_NOTIFICATION);
_SendMessage(&message, B_URL_PROTOCOL_HEADERS_RECEIVED, caller); _SendMessage(&message, B_URL_PROTOCOL_HEADERS_RECEIVED, caller);
@@ -72,7 +72,7 @@ BUrlProtocolDispatchingListener::HeadersReceived(BUrlProtocol* caller)
void void
BUrlProtocolDispatchingListener::DataReceived(BUrlProtocol* caller, BUrlProtocolDispatchingListener::DataReceived(BUrlRequest* caller,
const char* data, ssize_t size) const char* data, ssize_t size)
{ {
BMessage message(B_URL_PROTOCOL_NOTIFICATION); BMessage message(B_URL_PROTOCOL_NOTIFICATION);
@@ -83,7 +83,7 @@ BUrlProtocolDispatchingListener::DataReceived(BUrlProtocol* caller,
void void
BUrlProtocolDispatchingListener::DownloadProgress(BUrlProtocol* caller, BUrlProtocolDispatchingListener::DownloadProgress(BUrlRequest* caller,
ssize_t bytesReceived, ssize_t bytesTotal) ssize_t bytesReceived, ssize_t bytesTotal)
{ {
BMessage message(B_URL_PROTOCOL_NOTIFICATION); BMessage message(B_URL_PROTOCOL_NOTIFICATION);
@@ -95,7 +95,7 @@ BUrlProtocolDispatchingListener::DownloadProgress(BUrlProtocol* caller,
void void
BUrlProtocolDispatchingListener::UploadProgress(BUrlProtocol* caller, BUrlProtocolDispatchingListener::UploadProgress(BUrlRequest* caller,
ssize_t bytesSent, ssize_t bytesTotal) ssize_t bytesSent, ssize_t bytesTotal)
{ {
BMessage message(B_URL_PROTOCOL_NOTIFICATION); BMessage message(B_URL_PROTOCOL_NOTIFICATION);
@@ -108,7 +108,7 @@ BUrlProtocolDispatchingListener::UploadProgress(BUrlProtocol* caller,
void void
BUrlProtocolDispatchingListener::RequestCompleted(BUrlProtocol* caller, BUrlProtocolDispatchingListener::RequestCompleted(BUrlRequest* caller,
bool success) bool success)
{ {
BMessage message(B_URL_PROTOCOL_NOTIFICATION); BMessage message(B_URL_PROTOCOL_NOTIFICATION);
@@ -120,7 +120,7 @@ BUrlProtocolDispatchingListener::RequestCompleted(BUrlProtocol* caller,
void void
BUrlProtocolDispatchingListener::_SendMessage(BMessage* message, BUrlProtocolDispatchingListener::_SendMessage(BMessage* message,
int8 notification, BUrlProtocol* caller) int8 notification, BUrlRequest* caller)
{ {
ASSERT(message != NULL); ASSERT(message != NULL);
@@ -9,62 +9,62 @@
#include <iostream> #include <iostream>
#include <cstdio> #include <cstdio>
#include <UrlProtocol.h> #include <UrlRequest.h>
#include <UrlProtocolListener.h> #include <UrlProtocolListener.h>
using namespace std; using namespace std;
void void
BUrlProtocolListener::ConnectionOpened(BUrlProtocol*) BUrlProtocolListener::ConnectionOpened(BUrlRequest*)
{ {
} }
void void
BUrlProtocolListener::HostnameResolved(BUrlProtocol*, const char*) BUrlProtocolListener::HostnameResolved(BUrlRequest*, const char*)
{ {
} }
void void
BUrlProtocolListener::ResponseStarted(BUrlProtocol*) BUrlProtocolListener::ResponseStarted(BUrlRequest*)
{ {
} }
void void
BUrlProtocolListener::HeadersReceived(BUrlProtocol*) BUrlProtocolListener::HeadersReceived(BUrlRequest*)
{ {
} }
void void
BUrlProtocolListener::DataReceived(BUrlProtocol*, const char*, ssize_t) BUrlProtocolListener::DataReceived(BUrlRequest*, const char*, ssize_t)
{ {
} }
void void
BUrlProtocolListener::DownloadProgress(BUrlProtocol*, ssize_t, ssize_t) BUrlProtocolListener::DownloadProgress(BUrlRequest*, ssize_t, ssize_t)
{ {
} }
void void
BUrlProtocolListener::UploadProgress(BUrlProtocol*, ssize_t, ssize_t) BUrlProtocolListener::UploadProgress(BUrlRequest*, ssize_t, ssize_t)
{ {
} }
void void
BUrlProtocolListener::RequestCompleted(BUrlProtocol*, bool) BUrlProtocolListener::RequestCompleted(BUrlRequest*, bool)
{ {
} }
void void
BUrlProtocolListener::DebugMessage(BUrlProtocol* caller, BUrlProtocolListener::DebugMessage(BUrlRequest* caller,
BUrlProtocolDebugMessage type, const char* text) BUrlProtocolDebugMessage type, const char* text)
{ {
switch (type) { switch (type) {
@@ -0,0 +1,35 @@
/*
* Copyright 2010-2013 Haiku Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Christophe Huriaux, [email protected]
* Adrien Destugues, [email protected]
*/
#include <UrlProtocolRoster.h>
#include <new>
#include <UrlRequest.h>
#include <HttpRequest.h>
#include <Debug.h>
/* static */ BUrlRequest*
BUrlProtocolRoster::MakeRequest(const BUrl& url,
BUrlProtocolListener* listener, BUrlContext* context)
{
BUrlResult* result = new BUrlResult(url);
// FIXME this is leaked
// TODO: instanciate the correct BUrlProtocol using add-on interface
if (url.Protocol() == "http") {
return new(std::nothrow) BHttpRequest(url, *result, false, "HTTP", listener,
context);
} else if (url.Protocol() == "https") {
return new(std::nothrow) BHttpRequest(url, *result, true, "HTTPS", listener,
context);
}
return NULL;
}
+219 -161
View File
@@ -6,240 +6,298 @@
* Christophe Huriaux, [email protected] * Christophe Huriaux, [email protected]
*/ */
#include <new>
#include <UrlRequest.h> #include <UrlRequest.h>
#include <UrlProtocolHttp.h>
#include <Debug.h> #include <Debug.h>
#include <stdio.h>
static const char* kProtocolThreadStrStatus[B_PROT_THREAD_STATUS__END+1]
= {
"Request successfully completed",
"Request running",
"Socket error",
"Connection failed",
"Hostname resolution failed",
"Network write failed",
"Network read failed",
"Out of memory",
"Protocol-specific error",
"Unknown error"
};
BUrlRequest::BUrlRequest(const BUrl& url, BUrlProtocolListener* listener, BUrlRequest::BUrlRequest(const BUrl& url, BUrlProtocolListener* listener,
BUrlContext* context) BUrlContext* context, BUrlResult& result, const char* threadName,
const char* protocolName)
: :
fListener(listener), fUrl(url),
fUrlProtocol(NULL), fResult(result),
fResult(url),
fContext(context), fContext(context),
fUrl(), fListener(listener),
fInitStatus(B_ERROR) fQuit(false),
fRunning(false),
fThreadId(0),
fThreadName(threadName),
fProtocol(protocolName)
{ {
SetUrl(url);
}
BUrlRequest::BUrlRequest(const BUrlRequest& other)
:
fListener(NULL),
fUrlProtocol(NULL),
fResult(other.fUrl),
fContext(),
fUrl(),
fInitStatus(B_ERROR)
{
*this = other;
} }
BUrlRequest::~BUrlRequest() BUrlRequest::~BUrlRequest()
{ {
if (fUrlProtocol != NULL)
delete fUrlProtocol;
} }
// #pragma mark Request parameters modification
// #pragma mark URL protocol thread management
status_t thread_id
BUrlRequest::SetUrl(const BUrl& url) BUrlRequest::Run()
{ {
fUrl = url; // Thread already running
fResult.SetUrl(url); if (fRunning) {
PRINT(("BUrlRequest::Run() : Oops, already running ! "
if (fUrlProtocol != NULL && url.Protocol() == fUrl.Protocol()) { "[urlProtocol=%p]!\n", this));
fUrlProtocol->SetUrl(url); return fThreadId;
return B_OK;
} }
fInitStatus = _SetupProtocol(); fThreadId = spawn_thread(BUrlRequest::_ThreadEntry, fThreadName,
return fInitStatus; B_NORMAL_PRIORITY, this);
}
if (fThreadId < B_OK)
return fThreadId;
void status_t launchErr = resume_thread(fThreadId);
BUrlRequest::SetContext(BUrlContext* context) if (launchErr < B_OK) {
{ PRINT(("BUrlRequest::Run() : Failed to resume thread %ld\n",
fContext = context; fThreadId));
return launchErr;
if (fUrlProtocol != NULL)
fUrlProtocol->SetContext(context);
}
void
BUrlRequest::SetProtocolListener(BUrlProtocolListener* listener)
{
fListener = listener;
if (fUrlProtocol != NULL)
fUrlProtocol->SetListener(listener);
}
bool
BUrlRequest::SetProtocolOption(int32 option, void* value)
{
if (fUrlProtocol == NULL)
return false;
fUrlProtocol->SetOption(option, value);
return true;
}
// #pragma mark Request parameters access
const BUrlProtocol*
BUrlRequest::Protocol()
{
return fUrlProtocol;
}
const BUrlResult&
BUrlRequest::Result()
{
return fResult;
}
const BUrl&
BUrlRequest::Url()
{
return fUrl;
}
// #pragma mark Request control
status_t
BUrlRequest::Start()
{
if (fUrlProtocol == NULL) {
PRINT(("BUrlRequest::Perform() : Oops, no BUrlProtocol defined!\n"));
return B_ERROR;
} }
thread_id protocolThread = fUrlProtocol->Run(); fRunning = true;
return fThreadId;
if (protocolThread < B_OK)
return protocolThread;
return B_OK;
} }
status_t status_t
BUrlRequest::Pause() BUrlRequest::Pause()
{ {
if (fUrlProtocol == NULL) // TODO
return B_ERROR; return B_ERROR;
return fUrlProtocol->Pause();
} }
status_t status_t
BUrlRequest::Resume() BUrlRequest::Resume()
{ {
if (fUrlProtocol == NULL) // TODO
return B_ERROR; return B_ERROR;
return fUrlProtocol->Resume();
} }
status_t status_t
BUrlRequest::Abort() BUrlRequest::Stop()
{ {
if (fUrlProtocol == NULL) if (!fRunning)
return B_ERROR; return B_ERROR;
status_t returnCode = fUrlProtocol->Stop(); status_t threadStatus = B_OK;
delete fUrlProtocol; fQuit = true;
fUrlProtocol = NULL;
return returnCode; wait_for_thread(fThreadId, &threadStatus);
return threadStatus;
} }
// #pragma mark Request informations // #pragma mark URL protocol parameters modification
status_t status_t
BUrlRequest::InitCheck() const BUrlRequest::SetUrl(const BUrl& url)
{ {
return fInitStatus; // We should avoid to change URL while the thread is running ...
if (IsRunning())
return B_ERROR;
fUrl = url;
return B_OK;
} }
status_t
BUrlRequest::SetResult(BUrlResult& result)
{
if (IsRunning())
return B_ERROR;
fResult = result;
return B_OK;
}
status_t
BUrlRequest::SetContext(BUrlContext* context)
{
if (IsRunning())
return B_ERROR;
fContext = context;
return B_OK;
}
status_t
BUrlRequest::SetListener(BUrlProtocolListener* listener)
{
if (IsRunning())
return B_ERROR;
fListener = listener;
return B_OK;
}
// #pragma mark URL protocol parameters access
const BUrl&
BUrlRequest::Url() const
{
return fUrl;
}
BUrlResult&
BUrlRequest::Result() const
{
return fResult;
}
BUrlContext*
BUrlRequest::Context() const
{
return fContext;
}
BUrlProtocolListener*
BUrlRequest::Listener() const
{
return fListener;
}
const BString&
BUrlRequest::Protocol() const
{
return fProtocol;
}
// #pragma mark URL protocol informations
bool bool
BUrlRequest::IsRunning() const BUrlRequest::IsRunning() const
{ {
if (fUrlProtocol == NULL) return fRunning;
return false;
return fUrlProtocol->IsRunning();
} }
status_t status_t
BUrlRequest::Status() const BUrlRequest::Status() const
{ {
if (fUrlProtocol == NULL) return fThreadStatus;
return B_ERROR;
return fUrlProtocol->Status();
} }
// #pragma mark Overloaded members const char*
BUrlRequest::StatusString(status_t threadStatus) const
BUrlRequest&
BUrlRequest::operator=(const BUrlRequest& other)
{ {
delete fUrlProtocol; if (threadStatus < B_PROT_THREAD_STATUS__BASE)
fUrlProtocol = NULL; threadStatus = B_PROT_THREAD_STATUS__END;
fUrl = other.fUrl; else if (threadStatus >= B_PROT_PROTOCOL_ERROR)
fListener = other.fListener; threadStatus = B_PROT_PROTOCOL_ERROR;
fContext = other.fContext;
fResult = BUrlResult(other.fUrl);
SetUrl(other.fUrl);
return *this; return kProtocolThreadStrStatus[threadStatus];
}
// #pragma mark Thread management
/*static*/ int32
BUrlRequest::_ThreadEntry(void* arg)
{
BUrlRequest* urlProtocol = reinterpret_cast<BUrlRequest*>(arg);
urlProtocol->fThreadStatus = B_PROT_RUNNING;
status_t protocolLoopExitStatus = urlProtocol->_ProtocolLoop();
urlProtocol->fRunning = false;
urlProtocol->fThreadStatus = protocolLoopExitStatus;
if (urlProtocol->fListener != NULL)
urlProtocol->fListener->RequestCompleted(urlProtocol,
protocolLoopExitStatus == B_PROT_SUCCESS);
return B_OK;
} }
status_t status_t
BUrlRequest::_SetupProtocol() BUrlRequest::_ProtocolLoop()
{ {
// TODO: instanciate the correct BUrlProtocol w/ the services roster // Dummy _ProtocolLoop
delete fUrlProtocol; while (!fQuit)
fUrlProtocol = NULL; snooze(1000);
if (fUrl.Protocol() == "http") return B_PROT_SUCCESS;
fUrlProtocol = new(std::nothrow) BUrlProtocolHttp(fUrl, false, "HTTP", }
fListener, fContext, &fResult);
else if (fUrl.Protocol() == "https")
fUrlProtocol = new(std::nothrow) BUrlProtocolHttp(fUrl, true, "HTTPS", void
fListener, fContext, &fResult); BUrlRequest::_EmitDebug(BUrlProtocolDebugMessage type,
else const char* format, ...)
return B_NO_HANDLER_FOR_PROTOCOL; {
if (fListener == NULL)
if (fUrlProtocol == NULL) return;
return B_NO_MEMORY;
va_list arguments;
return B_OK; va_start(arguments, format);
char debugMsg[256];
vsnprintf(debugMsg, 256, format, arguments);
fListener->DebugMessage(this, type, debugMsg);
va_end(arguments);
}
BMallocIO&
BUrlRequest::_ResultRawData()
{
return fResult.fRawData;
}
BHttpHeaders&
BUrlRequest::_ResultHeaders()
{
return fResult.fHeaders;
}
void
BUrlRequest::_SetResultStatusCode(int32 statusCode)
{
fResult.fStatusCode = statusCode;
}
BString&
BUrlRequest::_ResultStatusText()
{
return fResult.fStatusString;
} }
@@ -13,10 +13,12 @@
#define PRINT(x) printf x; #define PRINT(x) printf x;
BUrlSynchronousRequest::BUrlSynchronousRequest(BUrl& url) BUrlSynchronousRequest::BUrlSynchronousRequest(BUrlRequest& request)
: :
BUrlRequest(url, this), BUrlRequest(request.Url(), this, request.Context(), request.Result(),
fRequestComplete(false) "BUrlSynchronousRequest", request.Protocol()),
fRequestComplete(false),
fWrappedRequest(request)
{ {
} }
@@ -24,10 +26,16 @@ BUrlSynchronousRequest::BUrlSynchronousRequest(BUrl& url)
status_t status_t
BUrlSynchronousRequest::Perform() BUrlSynchronousRequest::Perform()
{ {
SetProtocolListener(this); fWrappedRequest.SetListener(this);
fRequestComplete = false; fRequestComplete = false;
return Start(); thread_id worker = fWrappedRequest.Run();
// TODO something to do with the thread_id maybe ?
if (worker < B_OK)
return worker;
else
return B_OK;
} }
@@ -42,35 +50,35 @@ BUrlSynchronousRequest::WaitUntilCompletion()
void void
BUrlSynchronousRequest::ConnectionOpened(BUrlProtocol*) BUrlSynchronousRequest::ConnectionOpened(BUrlRequest*)
{ {
PRINT(("SynchronousRequest::ConnectionOpened()\n")); PRINT(("SynchronousRequest::ConnectionOpened()\n"));
} }
void void
BUrlSynchronousRequest::HostnameResolved(BUrlProtocol*, const char* ip) BUrlSynchronousRequest::HostnameResolved(BUrlRequest*, const char* ip)
{ {
PRINT(("SynchronousRequest::HostnameResolved(%s)\n", ip)); PRINT(("SynchronousRequest::HostnameResolved(%s)\n", ip));
} }
void void
BUrlSynchronousRequest::ResponseStarted(BUrlProtocol*) BUrlSynchronousRequest::ResponseStarted(BUrlRequest*)
{ {
PRINT(("SynchronousRequest::ResponseStarted()\n")); PRINT(("SynchronousRequest::ResponseStarted()\n"));
} }
void void
BUrlSynchronousRequest::HeadersReceived(BUrlProtocol*) BUrlSynchronousRequest::HeadersReceived(BUrlRequest*)
{ {
PRINT(("SynchronousRequest::HeadersReceived()\n")); PRINT(("SynchronousRequest::HeadersReceived()\n"));
} }
void void
BUrlSynchronousRequest::DataReceived(BUrlProtocol*, const char*, BUrlSynchronousRequest::DataReceived(BUrlRequest*, const char*,
ssize_t size) ssize_t size)
{ {
PRINT(("SynchronousRequest::DataReceived(%zd)\n", size)); PRINT(("SynchronousRequest::DataReceived(%zd)\n", size));
@@ -78,7 +86,7 @@ BUrlSynchronousRequest::DataReceived(BUrlProtocol*, const char*,
void void
BUrlSynchronousRequest::DownloadProgress(BUrlProtocol*, BUrlSynchronousRequest::DownloadProgress(BUrlRequest*,
ssize_t bytesReceived, ssize_t bytesTotal) ssize_t bytesReceived, ssize_t bytesTotal)
{ {
PRINT(("SynchronousRequest::DownloadProgress(%zd, %zd)\n", bytesReceived, PRINT(("SynchronousRequest::DownloadProgress(%zd, %zd)\n", bytesReceived,
@@ -87,7 +95,7 @@ BUrlSynchronousRequest::DownloadProgress(BUrlProtocol*,
void void
BUrlSynchronousRequest::UploadProgress(BUrlProtocol*, ssize_t bytesSent, BUrlSynchronousRequest::UploadProgress(BUrlRequest*, ssize_t bytesSent,
ssize_t bytesTotal) ssize_t bytesTotal)
{ {
PRINT(("SynchronousRequest::UploadProgress(%zd, %zd)\n", bytesSent, PRINT(("SynchronousRequest::UploadProgress(%zd, %zd)\n", bytesSent,
@@ -96,7 +104,7 @@ BUrlSynchronousRequest::UploadProgress(BUrlProtocol*, ssize_t bytesSent,
void void
BUrlSynchronousRequest::RequestCompleted(BUrlProtocol* caller, bool success) BUrlSynchronousRequest::RequestCompleted(BUrlRequest* caller, bool success)
{ {
PRINT(("SynchronousRequest::RequestCompleted(%s) : %s\n", (success?"true":"false"), PRINT(("SynchronousRequest::RequestCompleted(%s) : %s\n", (success?"true":"false"),
caller->StatusString(caller->Status()))); caller->StatusString(caller->Status())));