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
status_t MarkAsFile(const BString& filename,
const BString& mimeType);
status_t MarkAsFile(const BString& filename);
const BString& mimeType = "");
void UnmarkAsFile();
status_t CopyBuffer();
@@ -14,22 +14,34 @@
#include <HttpHeaders.h>
#include <NetBuffer.h>
#include <NetworkAddress.h>
#include <UrlProtocol.h>
#include <UrlRequest.h>
class BAbstractSocket;
class BUrlProtocolHttp : public BUrlProtocol {
class BHttpRequest : public BUrlRequest {
public:
BUrlProtocolHttp(BUrl& url, bool ssl = false,
BHttpRequest(const BUrl& url,
BUrlResult& result, bool ssl = false,
const char *protocolName = "HTTP",
BUrlProtocolListener* listener = NULL,
BUrlContext* context = NULL,
BUrlResult* result = NULL);
virtual ~BUrlProtocolHttp();
BUrlContext* context = NULL);
virtual ~BHttpRequest();
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 IsSuccessStatusCode(int16 code);
@@ -89,6 +101,7 @@ private:
BHttpHeaders* fOptHeaders;
BHttpForm* fOptPostFields;
BDataIO* fOptInputData;
ssize_t fOptInputDataSize;
bool fOptSetCookies : 1;
bool fOptFollowLocation : 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);
virtual ~BUrlProtocolAsynchronousListener();
virtual void ConnectionOpened(BUrlProtocol* caller);
virtual void HostnameResolved(BUrlProtocol* caller,
virtual void ConnectionOpened(BUrlRequest* caller);
virtual void HostnameResolved(BUrlRequest* caller,
const char* ip);
virtual void ResponseStarted(BUrlProtocol* caller);
virtual void HeadersReceived(BUrlProtocol* caller);
virtual void DataReceived(BUrlProtocol* caller,
virtual void ResponseStarted(BUrlRequest* caller);
virtual void HeadersReceived(BUrlRequest* caller);
virtual void DataReceived(BUrlRequest* caller,
const char* data, ssize_t size);
virtual void DownloadProgress(BUrlProtocol* caller,
virtual void DownloadProgress(BUrlRequest* caller,
ssize_t bytesReceived, ssize_t bytesTotal);
virtual void UploadProgress(BUrlProtocol* caller,
virtual void UploadProgress(BUrlRequest* caller,
ssize_t bytesSent, ssize_t bytesTotal);
virtual void RequestCompleted(BUrlProtocol* caller,
virtual void RequestCompleted(BUrlRequest* caller,
bool success);
// Synchronous listener access
@@ -38,26 +38,23 @@ public:
const BMessenger& messenger);
virtual ~BUrlProtocolDispatchingListener();
virtual void ConnectionOpened(BUrlProtocol* caller);
virtual void HostnameResolved(BUrlProtocol* caller,
virtual void ConnectionOpened(BUrlRequest* caller);
virtual void HostnameResolved(BUrlRequest* caller,
const char* ip);
virtual void ResponseStarted(BUrlProtocol* caller);
virtual void HeadersReceived(BUrlProtocol* caller);
virtual void DataReceived(BUrlProtocol* caller,
virtual void ResponseStarted(BUrlRequest* caller);
virtual void HeadersReceived(BUrlRequest* caller);
virtual void DataReceived(BUrlRequest* caller,
const char* data, ssize_t size);
virtual void DownloadProgress(BUrlProtocol* caller,
virtual void DownloadProgress(BUrlRequest* caller,
ssize_t bytesReceived, ssize_t bytesTotal);
virtual void UploadProgress(BUrlProtocol* caller,
virtual void UploadProgress(BUrlRequest* caller,
ssize_t bytesSent, ssize_t bytesTotal);
virtual void RequestCompleted(BUrlProtocol* caller,
virtual void RequestCompleted(BUrlRequest* caller,
bool success);
virtual void DebugMessage(BUrlProtocol*,
BUrlProtocolDebugMessage,
const char*) { }
private:
void _SendMessage(BMessage* message,
int8 notification, BUrlProtocol* caller);
int8 notification, BUrlRequest* caller);
private:
BMessenger fMessenger;
+19 -19
View File
@@ -9,7 +9,7 @@
#include <stddef.h>
#include <cstdlib>
class BUrlProtocol;
class BUrlRequest;
enum BUrlProtocolDebugMessage {
@@ -24,15 +24,15 @@ enum BUrlProtocolDebugMessage {
class BUrlProtocolListener {
public:
/*
/**
ConnectionOpened()
Frequency: Once
Called when the socket is opened.
*/
virtual void ConnectionOpened(BUrlProtocol* caller);
virtual void ConnectionOpened(BUrlRequest* caller);
/*
/**
HostnameResolved(ip)
Frequency: Once
Parameters: ip String representing the IP address of the resource
@@ -40,28 +40,28 @@ public:
Called when the final IP is discovered
*/
virtual void HostnameResolved(BUrlProtocol* caller,
virtual void HostnameResolved(BUrlRequest* caller,
const char* ip);
/*
/**
ReponseStarted()
Frequency: Once
Called when the request has been emitted and the server begins to
reply. Typically when the HTTP status code is received.
*/
virtual void ResponseStarted(BUrlProtocol* caller);
virtual void ResponseStarted(BUrlRequest* caller);
/*
/**
HeadersReceived()
Frequency: Once
Called when all the server response metadata (such as headers) have
been read and parsed.
*/
virtual void HeadersReceived(BUrlProtocol* caller);
virtual void HeadersReceived(BUrlRequest* caller);
/*
/**
DataReceived(data, size)
Frequency: Zero or more
Parameters: data Pointer to the data block in memory
@@ -69,10 +69,10 @@ public:
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);
/*
/**
DownloadProgress(bytesReceived, bytesTotal)
Frequency: Once or more
Parameters: bytesReceived Number of data bytes received
@@ -80,10 +80,10 @@ public:
Called each time a data block is received.
*/
virtual void DownloadProgress(BUrlProtocol* caller,
virtual void DownloadProgress(BUrlRequest* caller,
ssize_t bytesReceived, ssize_t bytesTotal);
/*
/**
UploadProgress(bytesSent, bytesTotal)
Frequency: Once or more
Parameters: bytesSent Number of data bytes sent
@@ -91,10 +91,10 @@ public:
Called each time a data block is emitted.
*/
virtual void UploadProgress(BUrlProtocol* caller,
virtual void UploadProgress(BUrlRequest* caller,
ssize_t bytesSent, ssize_t bytesTotal);
/*
/**
RequestCompleted(success)
Frequency: Once
Parameters: success true if the resource have been successfully
@@ -102,17 +102,17 @@ public:
Called once the request is complete.
*/
virtual void RequestCompleted(BUrlProtocol* caller,
virtual void RequestCompleted(BUrlRequest* caller,
bool success);
/*
/**
DebugMessage(type, text)
Frequency: zero or more
Parameters: type Type of the verbose message (see BUrlProtocolDebug)
Called each time a debug message is emitted
*/
virtual void DebugMessage(BUrlProtocol* caller,
virtual void DebugMessage(BUrlRequest* caller,
BUrlProtocolDebugMessage type,
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_
#include <HttpHeaders.h>
#include <Url.h>
#include <UrlResult.h>
#include <UrlContext.h>
#include <UrlProtocol.h>
#include <UrlProtocolListener.h>
enum {
B_NO_HANDLER_FOR_PROTOCOL = B_ERROR
};
#include <OS.h>
class BUrlRequest {
public:
BUrlRequest(const BUrl& url,
BUrlProtocolListener* listener = NULL,
BUrlContext* context = NULL);
BUrlRequest(const BUrlRequest& other);
BUrlProtocolListener* listener,
BUrlContext* context,
BUrlResult& result,
const char* threadName,
const char* protocolName);
virtual ~BUrlRequest();
// Request parameters modification
status_t SetUrl(const BUrl& url);
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();
// URL protocol thread management
virtual thread_id Run();
virtual status_t Pause();
virtual status_t Resume();
virtual status_t Abort();
virtual status_t Stop();
// Request informations
virtual status_t InitCheck() const;
// 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;
// Overloaded members
BUrlRequest& operator=(const BUrlRequest& other);
virtual const char* StatusString(status_t threadStatus)
const;
protected:
BUrlProtocolListener* fListener;
BUrlProtocol* fUrlProtocol;
BUrlResult fResult;
BUrlContext* fContext;
BUrl fUrl;
status_t fInitStatus;
static int32 _ThreadEntry(void* arg);
virtual status_t _ProtocolLoop();
virtual void _EmitDebug(BUrlProtocolDebugMessage type,
const char* format, ...);
private:
status_t _SetupProtocol();
// 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
};
#endif // _B_URL_REQUEST_H_
+2 -2
View File
@@ -14,11 +14,11 @@
#include <Url.h>
class BUrlProtocol;
class BUrlRequest;
class BUrlResult {
friend class BUrlProtocol;
friend class BUrlRequest;
public:
BUrlResult(const BUrl& url);
+10 -9
View File
@@ -12,7 +12,7 @@
class BUrlSynchronousRequest : public BUrlRequest, public BUrlProtocolListener {
public:
BUrlSynchronousRequest(BUrl& url);
BUrlSynchronousRequest(BUrlRequest& asynchronousRequest);
virtual ~BUrlSynchronousRequest() { };
// Synchronous wait
@@ -20,23 +20,24 @@ public:
virtual status_t WaitUntilCompletion();
// Protocol hooks
virtual void ConnectionOpened(BUrlProtocol* caller);
virtual void HostnameResolved(BUrlProtocol* caller,
virtual void ConnectionOpened(BUrlRequest* caller);
virtual void HostnameResolved(BUrlRequest* caller,
const char* ip);
virtual void ResponseStarted(BUrlProtocol* caller);
virtual void HeadersReceived(BUrlProtocol* caller);
virtual void DataReceived(BUrlProtocol* caller,
virtual void ResponseStarted(BUrlRequest* caller);
virtual void HeadersReceived(BUrlRequest* caller);
virtual void DataReceived(BUrlRequest* caller,
const char* data, ssize_t size);
virtual void DownloadProgress(BUrlProtocol* caller,
virtual void DownloadProgress(BUrlRequest* caller,
ssize_t bytesReceived, ssize_t bytesTotal);
virtual void UploadProgress(BUrlProtocol* caller,
virtual void UploadProgress(BUrlRequest* caller,
ssize_t bytesSent, ssize_t bytesTotal);
virtual void RequestCompleted(BUrlProtocol* caller,
virtual void RequestCompleted(BUrlRequest* caller,
bool success);
protected:
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
BHttpFormData::UnmarkAsFile()
{
@@ -277,6 +277,8 @@ BHttpHeaders::Clear()
BHttpHeaders&
BHttpHeaders::operator=(const BHttpHeaders& other)
{
Clear();
for (int32 i = 0; i < other.CountHeaders(); i++)
AddHeader(other.HeaderAt(i).Name(), other.HeaderAt(i).Value());
@@ -17,10 +17,7 @@
#include <File.h>
#include <Socket.h>
#include <SecureSocket.h>
#include <UrlProtocolHttp.h>
using BPrivate::BUrlProtocolOption;
#include <HttpRequest.h>
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,
BUrlContext* context, BUrlResult* result)
BUrlContext* context)
:
BUrlProtocol(url, listener, context, result, "BUrlProtocol.HTTP", protocolName),
BUrlRequest(url, listener, context, result, "BUrlProtocol.HTTP", protocolName),
fSSL(ssl),
fRequestMethod(B_HTTP_GET),
fHttpVersion(B_HTTP_11)
@@ -48,83 +45,109 @@ BUrlProtocolHttp::BUrlProtocolHttp(BUrl& url, bool ssl,
}
BUrlProtocolHttp::~BUrlProtocolHttp()
BHttpRequest::~BHttpRequest()
{
delete fSocket;
}
status_t
BUrlProtocolHttp::SetOption(uint32 name, void* value)
void
BHttpRequest::SetMethod(int8 method)
{
BUrlProtocolOption option(value);
fRequestMethod = method;
}
switch (name) {
case B_HTTPOPT_METHOD:
fRequestMethod = option.Int8();
break;
case B_HTTPOPT_FOLLOWLOCATION:
fOptFollowLocation = option.Bool();
break;
void
BHttpRequest::SetFollowLocation(bool follow)
{
fOptFollowLocation = follow;
}
case B_HTTPOPT_MAXREDIRS:
fOptMaxRedirs = option.Int8();
break;
case B_HTTPOPT_REFERER:
fOptReferer = option.String();
break;
void
BHttpRequest::SetMaxRedirections(int8 redirections)
{
fOptMaxRedirs = redirections;
}
case B_HTTPOPT_USERAGENT:
fOptUserAgent = option.String();
break;
case B_HTTPOPT_HEADERS:
fOptHeaders = reinterpret_cast<BHttpHeaders*>(option.Pointer());
break;
void
BHttpRequest::SetReferrer(const BString& referrer)
{
fOptReferer = referrer;
}
case B_HTTPOPT_DISCARD_DATA:
fOptDiscardData = option.Bool();
break;
case B_HTTPOPT_DISABLE_LISTENER:
fOptDisableListener = option.Bool();
break;
void
BHttpRequest::SetUserAgent(const BString& agent)
{
fOptUserAgent = agent;
}
case B_HTTPOPT_AUTOREFERER:
fOptAutoReferer = option.Bool();
break;
case B_HTTPOPT_POSTFIELDS:
fOptPostFields = reinterpret_cast<BHttpForm*>(option.Pointer());
void
BHttpRequest::SetHeaders(BHttpHeaders* headers)
{
fOptHeaders = headers;
}
if (fOptPostFields != NULL)
fRequestMethod = B_HTTP_POST;
break;
case B_HTTPOPT_INPUTDATA:
fOptInputData = reinterpret_cast<BDataIO*>(option.Pointer());
break;
void
BHttpRequest::SetDiscardData(bool discard)
{
fOptDiscardData = discard;
}
case B_HTTPOPT_AUTHUSERNAME:
fOptUsername = option.String();
break;
case B_HTTPOPT_AUTHPASSWORD:
fOptPassword = option.String();
break;
void
BHttpRequest::SetDisableListener(bool disable)
{
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
BUrlProtocolHttp::IsInformationalStatusCode(int16 code)
BHttpRequest::IsInformationalStatusCode(int16 code)
{
return (code >= B_HTTP_STATUS__INFORMATIONAL_BASE)
&& (code < B_HTTP_STATUS__INFORMATIONAL_END);
@@ -132,7 +155,7 @@ BUrlProtocolHttp::IsInformationalStatusCode(int16 code)
/*static*/ bool
BUrlProtocolHttp::IsSuccessStatusCode(int16 code)
BHttpRequest::IsSuccessStatusCode(int16 code)
{
return (code >= B_HTTP_STATUS__SUCCESS_BASE)
&& (code < B_HTTP_STATUS__SUCCESS_END);
@@ -140,7 +163,7 @@ BUrlProtocolHttp::IsSuccessStatusCode(int16 code)
/*static*/ bool
BUrlProtocolHttp::IsRedirectionStatusCode(int16 code)
BHttpRequest::IsRedirectionStatusCode(int16 code)
{
return (code >= B_HTTP_STATUS__REDIRECTION_BASE)
&& (code < B_HTTP_STATUS__REDIRECTION_END);
@@ -148,7 +171,7 @@ BUrlProtocolHttp::IsRedirectionStatusCode(int16 code)
/*static*/ bool
BUrlProtocolHttp::IsClientErrorStatusCode(int16 code)
BHttpRequest::IsClientErrorStatusCode(int16 code)
{
return (code >= B_HTTP_STATUS__CLIENT_ERROR_BASE)
&& (code < B_HTTP_STATUS__CLIENT_ERROR_END);
@@ -156,7 +179,7 @@ BUrlProtocolHttp::IsClientErrorStatusCode(int16 code)
/*static*/ bool
BUrlProtocolHttp::IsServerErrorStatusCode(int16 code)
BHttpRequest::IsServerErrorStatusCode(int16 code)
{
return (code >= B_HTTP_STATUS__SERVER_ERROR_BASE)
&& (code < B_HTTP_STATUS__SERVER_ERROR_END);
@@ -164,17 +187,17 @@ BUrlProtocolHttp::IsServerErrorStatusCode(int16 code)
/*static*/ int16
BUrlProtocolHttp::StatusCodeClass(int16 code)
BHttpRequest::StatusCodeClass(int16 code)
{
if (BUrlProtocolHttp::IsInformationalStatusCode(code))
if (BHttpRequest::IsInformationalStatusCode(code))
return B_HTTP_STATUS_CLASS_INFORMATIONAL;
else if (BUrlProtocolHttp::IsSuccessStatusCode(code))
else if (BHttpRequest::IsSuccessStatusCode(code))
return B_HTTP_STATUS_CLASS_SUCCESS;
else if (BUrlProtocolHttp::IsRedirectionStatusCode(code))
else if (BHttpRequest::IsRedirectionStatusCode(code))
return B_HTTP_STATUS_CLASS_REDIRECTION;
else if (BUrlProtocolHttp::IsClientErrorStatusCode(code))
else if (BHttpRequest::IsClientErrorStatusCode(code))
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_INVALID;
@@ -182,12 +205,12 @@ BUrlProtocolHttp::StatusCodeClass(int16 code)
const char*
BUrlProtocolHttp::StatusString(status_t threadStatus) const
BHttpRequest::StatusString(status_t threadStatus) const
{
if (threadStatus < B_PROT_THREAD_STATUS__END)
return BUrlProtocol::StatusString(threadStatus);
return BUrlRequest::StatusString(threadStatus);
else if (threadStatus >= B_PROT_HTTP_THREAD_STATUS__END)
return BUrlProtocol::StatusString(-1);
return BUrlRequest::StatusString(-1);
else
return kHttpProtocolThreadStrStatus[threadStatus
- B_PROT_THREAD_STATUS__END];
@@ -195,7 +218,7 @@ BUrlProtocolHttp::StatusString(status_t threadStatus) const
void
BUrlProtocolHttp::_ResetOptions()
BHttpRequest::_ResetOptions()
{
fOptFollowLocation = true;
fOptMaxRedirs = 8;
@@ -215,7 +238,7 @@ BUrlProtocolHttp::_ResetOptions()
#include <stdio.h>
status_t
BUrlProtocolHttp::_ProtocolLoop()
BHttpRequest::_ProtocolLoop()
{
printf("UHP[%p]::{Loop} %s\n", this, fUrl.UrlString().String());
@@ -252,7 +275,7 @@ BUrlProtocolHttp::_ProtocolLoop()
if (fOptAutoReferer)
fOptReferer = fUrl.UrlString();
switch (StatusCodeClass(fResult->StatusCode())) {
switch (StatusCodeClass(fResult.StatusCode())) {
case B_HTTP_STATUS_CLASS_INFORMATIONAL:
// Header 100:continue should have been
// handled in the _MakeRequest read loop
@@ -268,7 +291,7 @@ BUrlProtocolHttp::_ProtocolLoop()
// TODO: Some browsers seems to translate POST requests to
// 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"];
// Absolute path
@@ -289,7 +312,7 @@ BUrlProtocolHttp::_ProtocolLoop()
break;
case B_HTTP_STATUS_CLASS_CLIENT_ERROR:
switch (fResult->StatusCode()) {
switch (fResult.StatusCode()) {
case B_HTTP_STATUS_UNAUTHORIZED:
if (fAuthentication.Method() != B_HTTP_AUTHENTICATION_NONE) {
newRequest = false;
@@ -321,7 +344,7 @@ BUrlProtocolHttp::_ProtocolLoop()
"%ld headers and %ld bytes of data remaining",
fHeaders.CountHeaders(), fInputBuffer.Size());
if (fResult->StatusCode() == 404)
if (fResult.StatusCode() == 404)
return B_PROT_HTTP_NOT_FOUND;
return B_PROT_SUCCESS;
@@ -329,7 +352,7 @@ BUrlProtocolHttp::_ProtocolLoop()
bool
BUrlProtocolHttp::_ResolveHostName()
BHttpRequest::_ResolveHostName()
{
_EmitDebug(B_URL_PROTOCOL_DEBUG_TEXT, "Resolving %s",
fUrl.UrlString().String());
@@ -357,7 +380,7 @@ BUrlProtocolHttp::_ResolveHostName()
status_t
BUrlProtocolHttp::_MakeRequest()
BHttpRequest::_MakeRequest()
{
_EmitDebug(B_URL_PROTOCOL_DEBUG_TEXT, "Connection to %s on port %d.",
fUrl.Authority().String(), fRemoteAddr.Port());
@@ -442,13 +465,19 @@ BUrlProtocolHttp::_MakeRequest()
read = fOptInputData->Read(outputTempBuffer, 1024);
if (read > 0) {
char hexSize[16];
size_t hexLength = sprintf(hexSize, "%ld", read);
if (fOptInputDataSize < 0)
{
// Chunked transfer
char hexSize[16];
size_t hexLength = sprintf(hexSize, "%ld", read);
fSocket->Write(hexSize, hexLength);
fSocket->Write("\r\n", 2);
fSocket->Write(outputTempBuffer, read);
fSocket->Write("\r\n", 2);
fSocket->Write(hexSize, hexLength);
fSocket->Write("\r\n", 2);
fSocket->Write(outputTempBuffer, read);
fSocket->Write("\r\n", 2);
} else {
fSocket->Write(outputTempBuffer, read);
}
}
}
@@ -626,7 +655,7 @@ BUrlProtocolHttp::_MakeRequest()
status_t
BUrlProtocolHttp::_GetLine(BString& destString)
BHttpRequest::_GetLine(BString& destString)
{
// Find a complete line in inputBuffer
uint32 characterIndex = 0;
@@ -653,7 +682,7 @@ BUrlProtocolHttp::_GetLine(BString& destString)
void
BUrlProtocolHttp::_ParseStatus()
BHttpRequest::_ParseStatus()
{
// Status line should be formatted like: HTTP/M.m SSS ...
// With: M = Major version of the protocol
@@ -682,7 +711,7 @@ BUrlProtocolHttp::_ParseStatus()
void
BUrlProtocolHttp::_ParseHeaders()
BHttpRequest::_ParseHeaders()
{
BString currentHeader;
if (_GetLine(currentHeader) == B_ERROR)
@@ -700,7 +729,7 @@ BUrlProtocolHttp::_ParseHeaders()
void
BUrlProtocolHttp::_CreateRequest()
BHttpRequest::_CreateRequest()
{
BString request;
@@ -748,7 +777,7 @@ BUrlProtocolHttp::_CreateRequest()
void
BUrlProtocolHttp::_AddHeaders()
BHttpRequest::_AddHeaders()
{
// HTTP 1.1 additional headers
if (fHttpVersion == B_HTTP_11) {
@@ -813,8 +842,14 @@ BUrlProtocolHttp::_AddHeaders()
fOutputHeaders.AddHeader("Content-Length",
fOptPostFields->ContentLength());
} else if (fOptInputData != NULL
&& (fRequestMethod == B_HTTP_POST || fRequestMethod == B_HTTP_PUT))
fOutputHeaders.AddHeader("Transfer-Encoding", "chunked");
&& (fRequestMethod == B_HTTP_POST || fRequestMethod == B_HTTP_PUT))
{
if(fOptInputDataSize >= 0) {
fOutputHeaders.AddHeader("Content-Length", fOptInputDataSize);
} else {
fOutputHeaders.AddHeader("Transfer-Encoding", "chunked");
}
}
// Optional headers specified by the user
if (fOptHeaders != NULL) {
@@ -850,7 +885,7 @@ BUrlProtocolHttp::_AddHeaders()
void
BUrlProtocolHttp::_AddOutputBufferLine(const char* line)
BHttpRequest::_AddOutputBufferLine(const char* line)
{
_EmitDebug(B_URL_PROTOCOL_DEBUG_HEADER_OUT, "%s", line);
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
# linking against libcrypto.so and only the add-on should link
# 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
HttpHeaders.cpp
HttpForm.cpp
HttpRequest.cpp
HttpTime.cpp
$(md5Sources)
Url.cpp
UrlContext.cpp
UrlProtocol.cpp
UrlProtocolAsynchronousListener.cpp
UrlProtocolDispatchingListener.cpp
UrlProtocolHttp.cpp # TODO: -> add-on, See above.
UrlProtocolListener.cpp
UrlProtocolRoster.cpp
UrlRequest.cpp
UrlResult.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
BUrlProtocolAsynchronousListener::ConnectionOpened(BUrlProtocol*)
BUrlProtocolAsynchronousListener::ConnectionOpened(BUrlRequest*)
{
}
void
BUrlProtocolAsynchronousListener::HostnameResolved(BUrlProtocol*, const char*)
BUrlProtocolAsynchronousListener::HostnameResolved(BUrlRequest*, const char*)
{
}
void
BUrlProtocolAsynchronousListener::ResponseStarted(BUrlProtocol*)
BUrlProtocolAsynchronousListener::ResponseStarted(BUrlRequest*)
{
}
void
BUrlProtocolAsynchronousListener::HeadersReceived(BUrlProtocol*)
BUrlProtocolAsynchronousListener::HeadersReceived(BUrlRequest*)
{
}
void
BUrlProtocolAsynchronousListener::DataReceived(BUrlProtocol*, const char*,
BUrlProtocolAsynchronousListener::DataReceived(BUrlRequest*, const char*,
ssize_t)
{
}
void
BUrlProtocolAsynchronousListener::DownloadProgress(BUrlProtocol*, ssize_t,
BUrlProtocolAsynchronousListener::DownloadProgress(BUrlRequest*, ssize_t,
ssize_t)
{
}
void
BUrlProtocolAsynchronousListener::UploadProgress(BUrlProtocol*, ssize_t,
BUrlProtocolAsynchronousListener::UploadProgress(BUrlRequest*, ssize_t,
ssize_t)
{
}
void
BUrlProtocolAsynchronousListener::RequestCompleted(BUrlProtocol*, bool)
BUrlProtocolAsynchronousListener::RequestCompleted(BUrlRequest*, bool)
{
}
@@ -114,7 +114,7 @@ BUrlProtocolAsynchronousListener::MessageReceived(BMessage* message)
return;
}
BUrlProtocol* caller;
BUrlRequest* caller;
if (message->FindPointer(kUrlProtocolCaller,
reinterpret_cast<void**>(&caller)) != B_OK)
return;
@@ -37,7 +37,7 @@ BUrlProtocolDispatchingListener::~BUrlProtocolDispatchingListener()
void
BUrlProtocolDispatchingListener::ConnectionOpened(BUrlProtocol* caller)
BUrlProtocolDispatchingListener::ConnectionOpened(BUrlRequest* caller)
{
BMessage message(B_URL_PROTOCOL_NOTIFICATION);
_SendMessage(&message, B_URL_PROTOCOL_CONNECTION_OPENED, caller);
@@ -45,7 +45,7 @@ BUrlProtocolDispatchingListener::ConnectionOpened(BUrlProtocol* caller)
void
BUrlProtocolDispatchingListener::HostnameResolved(BUrlProtocol* caller,
BUrlProtocolDispatchingListener::HostnameResolved(BUrlRequest* caller,
const char* ip)
{
BMessage message(B_URL_PROTOCOL_NOTIFICATION);
@@ -56,7 +56,7 @@ BUrlProtocolDispatchingListener::HostnameResolved(BUrlProtocol* caller,
void
BUrlProtocolDispatchingListener::ResponseStarted(BUrlProtocol* caller)
BUrlProtocolDispatchingListener::ResponseStarted(BUrlRequest* caller)
{
BMessage message(B_URL_PROTOCOL_NOTIFICATION);
_SendMessage(&message, B_URL_PROTOCOL_RESPONSE_STARTED, caller);
@@ -64,7 +64,7 @@ BUrlProtocolDispatchingListener::ResponseStarted(BUrlProtocol* caller)
void
BUrlProtocolDispatchingListener::HeadersReceived(BUrlProtocol* caller)
BUrlProtocolDispatchingListener::HeadersReceived(BUrlRequest* caller)
{
BMessage message(B_URL_PROTOCOL_NOTIFICATION);
_SendMessage(&message, B_URL_PROTOCOL_HEADERS_RECEIVED, caller);
@@ -72,7 +72,7 @@ BUrlProtocolDispatchingListener::HeadersReceived(BUrlProtocol* caller)
void
BUrlProtocolDispatchingListener::DataReceived(BUrlProtocol* caller,
BUrlProtocolDispatchingListener::DataReceived(BUrlRequest* caller,
const char* data, ssize_t size)
{
BMessage message(B_URL_PROTOCOL_NOTIFICATION);
@@ -83,7 +83,7 @@ BUrlProtocolDispatchingListener::DataReceived(BUrlProtocol* caller,
void
BUrlProtocolDispatchingListener::DownloadProgress(BUrlProtocol* caller,
BUrlProtocolDispatchingListener::DownloadProgress(BUrlRequest* caller,
ssize_t bytesReceived, ssize_t bytesTotal)
{
BMessage message(B_URL_PROTOCOL_NOTIFICATION);
@@ -95,7 +95,7 @@ BUrlProtocolDispatchingListener::DownloadProgress(BUrlProtocol* caller,
void
BUrlProtocolDispatchingListener::UploadProgress(BUrlProtocol* caller,
BUrlProtocolDispatchingListener::UploadProgress(BUrlRequest* caller,
ssize_t bytesSent, ssize_t bytesTotal)
{
BMessage message(B_URL_PROTOCOL_NOTIFICATION);
@@ -108,7 +108,7 @@ BUrlProtocolDispatchingListener::UploadProgress(BUrlProtocol* caller,
void
BUrlProtocolDispatchingListener::RequestCompleted(BUrlProtocol* caller,
BUrlProtocolDispatchingListener::RequestCompleted(BUrlRequest* caller,
bool success)
{
BMessage message(B_URL_PROTOCOL_NOTIFICATION);
@@ -120,7 +120,7 @@ BUrlProtocolDispatchingListener::RequestCompleted(BUrlProtocol* caller,
void
BUrlProtocolDispatchingListener::_SendMessage(BMessage* message,
int8 notification, BUrlProtocol* caller)
int8 notification, BUrlRequest* caller)
{
ASSERT(message != NULL);
@@ -9,62 +9,62 @@
#include <iostream>
#include <cstdio>
#include <UrlProtocol.h>
#include <UrlRequest.h>
#include <UrlProtocolListener.h>
using namespace std;
void
BUrlProtocolListener::ConnectionOpened(BUrlProtocol*)
BUrlProtocolListener::ConnectionOpened(BUrlRequest*)
{
}
void
BUrlProtocolListener::HostnameResolved(BUrlProtocol*, const char*)
BUrlProtocolListener::HostnameResolved(BUrlRequest*, const char*)
{
}
void
BUrlProtocolListener::ResponseStarted(BUrlProtocol*)
BUrlProtocolListener::ResponseStarted(BUrlRequest*)
{
}
void
BUrlProtocolListener::HeadersReceived(BUrlProtocol*)
BUrlProtocolListener::HeadersReceived(BUrlRequest*)
{
}
void
BUrlProtocolListener::DataReceived(BUrlProtocol*, const char*, ssize_t)
BUrlProtocolListener::DataReceived(BUrlRequest*, const char*, ssize_t)
{
}
void
BUrlProtocolListener::DownloadProgress(BUrlProtocol*, ssize_t, ssize_t)
BUrlProtocolListener::DownloadProgress(BUrlRequest*, ssize_t, ssize_t)
{
}
void
BUrlProtocolListener::UploadProgress(BUrlProtocol*, ssize_t, ssize_t)
BUrlProtocolListener::UploadProgress(BUrlRequest*, ssize_t, ssize_t)
{
}
void
BUrlProtocolListener::RequestCompleted(BUrlProtocol*, bool)
BUrlProtocolListener::RequestCompleted(BUrlRequest*, bool)
{
}
void
BUrlProtocolListener::DebugMessage(BUrlProtocol* caller,
BUrlProtocolListener::DebugMessage(BUrlRequest* caller,
BUrlProtocolDebugMessage type, const char* text)
{
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, c.huriaux@gmail.com
* Adrien Destugues, pulkomandy@pulkomandy.tk
*/
#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, c.huriaux@gmail.com
*/
#include <new>
#include <UrlRequest.h>
#include <UrlProtocolHttp.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,
BUrlContext* context)
BUrlContext* context, BUrlResult& result, const char* threadName,
const char* protocolName)
:
fListener(listener),
fUrlProtocol(NULL),
fResult(url),
fUrl(url),
fResult(result),
fContext(context),
fUrl(),
fInitStatus(B_ERROR)
fListener(listener),
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()
{
if (fUrlProtocol != NULL)
delete fUrlProtocol;
}
// #pragma mark Request parameters modification
// #pragma mark URL protocol thread management
status_t
BUrlRequest::SetUrl(const BUrl& url)
thread_id
BUrlRequest::Run()
{
fUrl = url;
fResult.SetUrl(url);
if (fUrlProtocol != NULL && url.Protocol() == fUrl.Protocol()) {
fUrlProtocol->SetUrl(url);
return B_OK;
// Thread already running
if (fRunning) {
PRINT(("BUrlRequest::Run() : Oops, already running ! "
"[urlProtocol=%p]!\n", this));
return fThreadId;
}
fInitStatus = _SetupProtocol();
return fInitStatus;
}
fThreadId = spawn_thread(BUrlRequest::_ThreadEntry, fThreadName,
B_NORMAL_PRIORITY, this);
if (fThreadId < B_OK)
return fThreadId;
void
BUrlRequest::SetContext(BUrlContext* context)
{
fContext = context;
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;
status_t launchErr = resume_thread(fThreadId);
if (launchErr < B_OK) {
PRINT(("BUrlRequest::Run() : Failed to resume thread %ld\n",
fThreadId));
return launchErr;
}
thread_id protocolThread = fUrlProtocol->Run();
if (protocolThread < B_OK)
return protocolThread;
return B_OK;
fRunning = true;
return fThreadId;
}
status_t
BUrlRequest::Pause()
{
if (fUrlProtocol == NULL)
return B_ERROR;
return fUrlProtocol->Pause();
// TODO
return B_ERROR;
}
status_t
BUrlRequest::Resume()
{
if (fUrlProtocol == NULL)
return B_ERROR;
return fUrlProtocol->Resume();
// TODO
return B_ERROR;
}
status_t
BUrlRequest::Abort()
BUrlRequest::Stop()
{
if (fUrlProtocol == NULL)
if (!fRunning)
return B_ERROR;
status_t returnCode = fUrlProtocol->Stop();
delete fUrlProtocol;
fUrlProtocol = NULL;
status_t threadStatus = B_OK;
fQuit = true;
return returnCode;
wait_for_thread(fThreadId, &threadStatus);
return threadStatus;
}
// #pragma mark Request informations
// #pragma mark URL protocol parameters modification
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
BUrlRequest::IsRunning() const
{
if (fUrlProtocol == NULL)
return false;
return fUrlProtocol->IsRunning();
return fRunning;
}
status_t
BUrlRequest::Status() const
{
if (fUrlProtocol == NULL)
return B_ERROR;
return fUrlProtocol->Status();
return fThreadStatus;
}
// #pragma mark Overloaded members
BUrlRequest&
BUrlRequest::operator=(const BUrlRequest& other)
const char*
BUrlRequest::StatusString(status_t threadStatus) const
{
delete fUrlProtocol;
fUrlProtocol = NULL;
fUrl = other.fUrl;
fListener = other.fListener;
fContext = other.fContext;
fResult = BUrlResult(other.fUrl);
SetUrl(other.fUrl);
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 *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
BUrlRequest::_SetupProtocol()
BUrlRequest::_ProtocolLoop()
{
// TODO: instanciate the correct BUrlProtocol w/ the services roster
delete fUrlProtocol;
fUrlProtocol = NULL;
// Dummy _ProtocolLoop
while (!fQuit)
snooze(1000);
if (fUrl.Protocol() == "http")
fUrlProtocol = new(std::nothrow) BUrlProtocolHttp(fUrl, false, "HTTP",
fListener, fContext, &fResult);
else if (fUrl.Protocol() == "https")
fUrlProtocol = new(std::nothrow) BUrlProtocolHttp(fUrl, true, "HTTPS",
fListener, fContext, &fResult);
else
return B_NO_HANDLER_FOR_PROTOCOL;
if (fUrlProtocol == NULL)
return B_NO_MEMORY;
return B_OK;
return B_PROT_SUCCESS;
}
void
BUrlRequest::_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&
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;
BUrlSynchronousRequest::BUrlSynchronousRequest(BUrl& url)
BUrlSynchronousRequest::BUrlSynchronousRequest(BUrlRequest& request)
:
BUrlRequest(url, this),
fRequestComplete(false)
BUrlRequest(request.Url(), this, request.Context(), request.Result(),
"BUrlSynchronousRequest", request.Protocol()),
fRequestComplete(false),
fWrappedRequest(request)
{
}
@@ -24,10 +26,16 @@ BUrlSynchronousRequest::BUrlSynchronousRequest(BUrl& url)
status_t
BUrlSynchronousRequest::Perform()
{
SetProtocolListener(this);
fWrappedRequest.SetListener(this);
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
BUrlSynchronousRequest::ConnectionOpened(BUrlProtocol*)
BUrlSynchronousRequest::ConnectionOpened(BUrlRequest*)
{
PRINT(("SynchronousRequest::ConnectionOpened()\n"));
}
void
BUrlSynchronousRequest::HostnameResolved(BUrlProtocol*, const char* ip)
BUrlSynchronousRequest::HostnameResolved(BUrlRequest*, const char* ip)
{
PRINT(("SynchronousRequest::HostnameResolved(%s)\n", ip));
}
void
BUrlSynchronousRequest::ResponseStarted(BUrlProtocol*)
BUrlSynchronousRequest::ResponseStarted(BUrlRequest*)
{
PRINT(("SynchronousRequest::ResponseStarted()\n"));
}
void
BUrlSynchronousRequest::HeadersReceived(BUrlProtocol*)
BUrlSynchronousRequest::HeadersReceived(BUrlRequest*)
{
PRINT(("SynchronousRequest::HeadersReceived()\n"));
}
void
BUrlSynchronousRequest::DataReceived(BUrlProtocol*, const char*,
BUrlSynchronousRequest::DataReceived(BUrlRequest*, const char*,
ssize_t size)
{
PRINT(("SynchronousRequest::DataReceived(%zd)\n", size));
@@ -78,7 +86,7 @@ BUrlSynchronousRequest::DataReceived(BUrlProtocol*, const char*,
void
BUrlSynchronousRequest::DownloadProgress(BUrlProtocol*,
BUrlSynchronousRequest::DownloadProgress(BUrlRequest*,
ssize_t bytesReceived, ssize_t bytesTotal)
{
PRINT(("SynchronousRequest::DownloadProgress(%zd, %zd)\n", bytesReceived,
@@ -87,7 +95,7 @@ BUrlSynchronousRequest::DownloadProgress(BUrlProtocol*,
void
BUrlSynchronousRequest::UploadProgress(BUrlProtocol*, ssize_t bytesSent,
BUrlSynchronousRequest::UploadProgress(BUrlRequest*, ssize_t bytesSent,
ssize_t bytesTotal)
{
PRINT(("SynchronousRequest::UploadProgress(%zd, %zd)\n", bytesSent,
@@ -96,7 +104,7 @@ BUrlSynchronousRequest::UploadProgress(BUrlProtocol*, ssize_t bytesSent,
void
BUrlSynchronousRequest::RequestCompleted(BUrlProtocol* caller, bool success)
BUrlSynchronousRequest::RequestCompleted(BUrlRequest* caller, bool success)
{
PRINT(("SynchronousRequest::RequestCompleted(%s) : %s\n", (success?"true":"false"),
caller->StatusString(caller->Status())));