BUrlRequest: fix various issues

* Remove unused headers interface from BUrlProtocol
* Change confusing function names
* Style fixes and whitespace cleanup
This commit is contained in:
Hamish Morrison
2013-02-10 20:46:24 +00:00
parent 344de4ccd1
commit 2675e31a0c
7 changed files with 324 additions and 362 deletions
+15 -19
View File
@@ -15,14 +15,14 @@
class BUrlProtocol { class BUrlProtocol {
public: public:
BUrlProtocol(const BUrl& url, BUrlProtocol(const BUrl& url,
BUrlProtocolListener* listener, BUrlProtocolListener* listener,
BUrlContext* context, BUrlContext* context,
BUrlResult* result, BUrlResult* result,
const char* threadName, const char* threadName,
const char* protocolName); const char* protocolName);
virtual ~BUrlProtocol(); virtual ~BUrlProtocol();
// URL protocol required members // URL protocol required members
// TODO: (stippi) I know it's sometimes appealing to have these // TODO: (stippi) I know it's sometimes appealing to have these
// "simplistic" methods that can do anything, but they remove // "simplistic" methods that can do anything, but they remove
@@ -39,7 +39,7 @@ public:
// is it here at all? Why not have non-virtual setters for specific // is it here at all? Why not have non-virtual setters for specific
// things, where the setter is properly named? // things, where the setter is properly named?
virtual status_t SetOption(uint32 name, void* value) = 0; virtual status_t SetOption(uint32 name, void* value) = 0;
// URL protocol thread management // URL protocol thread management
virtual thread_id Run(); virtual thread_id Run();
virtual status_t Pause(); virtual status_t Pause();
@@ -51,27 +51,25 @@ public:
status_t SetResult(BUrlResult* result); status_t SetResult(BUrlResult* result);
status_t SetContext(BUrlContext* context); status_t SetContext(BUrlContext* context);
status_t SetListener(BUrlProtocolListener* listener); status_t SetListener(BUrlProtocolListener* listener);
// URL protocol parameters access // URL protocol parameters access
const BUrl& Url() const; const BUrl& Url() const;
BUrlResult* Result() const; BUrlResult* Result() const;
BUrlContext* Context() const; BUrlContext* Context() const;
BUrlProtocolListener* Listener() const; BUrlProtocolListener* Listener() const;
const BString& Protocol() const; const BString& Protocol() const;
// TODO: Does not belong here.
BHttpHeaders& Headers() { return fRequestHeaders; }
// URL protocol informations // URL protocol informations
bool IsRunning() const; bool IsRunning() const;
status_t Status() const; status_t Status() const;
virtual const char* StatusString(status_t threadStatus) virtual const char* StatusString(status_t threadStatus)
const; const;
protected: protected:
static int32 _ThreadEntry(void* arg); static int32 _ThreadEntry(void* arg);
virtual status_t _ProtocolLoop(); virtual status_t _ProtocolLoop();
virtual void _EmitDebug(BUrlProtocolDebugMessage type, virtual void _EmitDebug(BUrlProtocolDebugMessage type,
const char* format, ...); const char* format, ...);
// URL result parameters access // URL result parameters access
@@ -79,15 +77,13 @@ protected:
BHttpHeaders& _ResultHeaders(); BHttpHeaders& _ResultHeaders();
void _SetResultStatusCode(int32 statusCode); void _SetResultStatusCode(int32 statusCode);
BString& _ResultStatusText(); BString& _ResultStatusText();
protected: protected:
BUrl fUrl; BUrl fUrl;
BHttpHeaders fRequestHeaders;
// TODO: Does not belong here.
BUrlResult* fResult; BUrlResult* fResult;
BUrlContext* fContext; BUrlContext* fContext;
BUrlProtocolListener* fListener; BUrlProtocolListener* fListener;
bool fQuit; bool fQuit;
bool fRunning; bool fRunning;
status_t fThreadStatus; status_t fThreadStatus;
@@ -110,7 +106,7 @@ enum {
B_PROT_WRITE_FAILED, B_PROT_WRITE_FAILED,
B_PROT_READ_FAILED, B_PROT_READ_FAILED,
B_PROT_NO_MEMORY, B_PROT_NO_MEMORY,
B_PROT_PROTOCOL_ERROR, B_PROT_PROTOCOL_ERROR,
// Thread status over this one are guaranteed to be // Thread status over this one are guaranteed to be
// errors // errors
B_PROT_THREAD_STATUS__END B_PROT_THREAD_STATUS__END
@@ -118,18 +114,18 @@ enum {
namespace BPrivate { namespace BPrivate {
class BUrlProtocolOption { class BUrlProtocolOption {
public: public:
BUrlProtocolOption(void* value) : fValuePtr(value) { } BUrlProtocolOption(void* value) : fValuePtr(value) { }
bool Bool() const { return *reinterpret_cast<bool*>(fValuePtr); } bool Bool() const { return *reinterpret_cast<bool*>(fValuePtr); }
int8 Int8() const { return *reinterpret_cast<int8*>(fValuePtr); } int8 Int8() const { return *reinterpret_cast<int8*>(fValuePtr); }
int16 Int16() const { return *reinterpret_cast<int16*>(fValuePtr); } int16 Int16() const { return *reinterpret_cast<int16*>(fValuePtr); }
int32 Int32() const { return *reinterpret_cast<int32*>(fValuePtr); } int32 Int32() const { return *reinterpret_cast<int32*>(fValuePtr); }
char* String() const { return reinterpret_cast<char*>(fValuePtr); } char* String() const { return reinterpret_cast<char*>(fValuePtr); }
void* Pointer() const { return fValuePtr; } void* Pointer() const { return fValuePtr; }
private: private:
void* fValuePtr; void* fValuePtr;
}; };
+29 -29
View File
@@ -30,7 +30,7 @@ public:
virtual ~BUrlProtocolHttp(); virtual ~BUrlProtocolHttp();
virtual status_t SetOption(uint32 option, void* value); virtual status_t SetOption(uint32 option, void* value);
static bool IsInformationalStatusCode(int16 code); static bool IsInformationalStatusCode(int16 code);
static bool IsSuccessStatusCode(int16 code); static bool IsSuccessStatusCode(int16 code);
static bool IsRedirectionStatusCode(int16 code); static bool IsRedirectionStatusCode(int16 code);
@@ -39,49 +39,49 @@ public:
static int16 StatusCodeClass(int16 code); static int16 StatusCodeClass(int16 code);
virtual const char* StatusString(status_t threadStatus) const; virtual const char* StatusString(status_t threadStatus) const;
private: private:
void _ResetOptions(); void _ResetOptions();
status_t _ProtocolLoop(); status_t _ProtocolLoop();
bool _ResolveHostName(); bool _ResolveHostName();
status_t _MakeRequest(); status_t _MakeRequest();
void _CreateRequest(); void _CreateRequest();
void _AddHeaders(); void _AddHeaders();
status_t _GetLine(BString& destString); status_t _GetLine(BString& destString);
void _ParseStatus(); void _ParseStatus();
void _ParseHeaders(); void _ParseHeaders();
void _CopyChunkInBuffer(char** buffer, void _CopyChunkInBuffer(char** buffer,
ssize_t* bytesReceived); ssize_t* bytesReceived);
void _AddOutputBufferLine(const char* line); void _AddOutputBufferLine(const char* line);
private: private:
BAbstractSocket* fSocket; BAbstractSocket* fSocket;
BNetworkAddress fRemoteAddr; BNetworkAddress fRemoteAddr;
bool fSSL; bool fSSL;
int8 fRequestMethod; int8 fRequestMethod;
int8 fHttpVersion; int8 fHttpVersion;
BString fOutputBuffer; BString fOutputBuffer;
BNetBuffer fInputBuffer; BNetBuffer fInputBuffer;
BHttpHeaders fHeaders; BHttpHeaders fHeaders;
BHttpAuthentication fAuthentication; BHttpAuthentication fAuthentication;
// Request status // Request status
BHttpHeaders fOutputHeaders; BHttpHeaders fOutputHeaders;
bool fStatusReceived; bool fStatusReceived;
bool fHeadersReceived; bool fHeadersReceived;
bool fContentReceived; bool fContentReceived;
bool fTrailingHeadersReceived; bool fTrailingHeadersReceived;
// Protocol options // Protocol options
uint8 fOptMaxRedirs; uint8 fOptMaxRedirs;
BString fOptReferer; BString fOptReferer;
@@ -128,21 +128,21 @@ enum {
enum { enum {
B_HTTPOPT_METHOD = 0, B_HTTPOPT_METHOD = 0,
// (int) Request method (see B_HTTP_GET, ...) // (int) Request method (see B_HTTP_GET, ...)
B_HTTPOPT_FOLLOWLOCATION, B_HTTPOPT_FOLLOWLOCATION,
// (bool) Follow Location: headers // (bool) Follow Location: headers
B_HTTPOPT_MAXREDIRS, B_HTTPOPT_MAXREDIRS,
// (int) Max relocation // (int) Max relocation
B_HTTPOPT_HEADERS, B_HTTPOPT_HEADERS,
// (BHttpHeaders*) Headers to be sent // (BHttpHeaders*) Headers to be sent
B_HTTPOPT_REFERER, B_HTTPOPT_REFERER,
// (string) Referer // (string) Referer
B_HTTPOPT_USERAGENT, B_HTTPOPT_USERAGENT,
// (string) User-Agent // (string) User-Agent
B_HTTPOPT_SETCOOKIES, B_HTTPOPT_SETCOOKIES,
// (bool) Send cookies from context // (bool) Send cookies from context
B_HTTPOPT_DISCARD_DATA, B_HTTPOPT_DISCARD_DATA,
// (bool) Discard incoming data (still notified) // (bool) Discard incoming data (still notified)
B_HTTPOPT_DISABLE_LISTENER, B_HTTPOPT_DISABLE_LISTENER,
// (bool) Don't send notification to the listener // (bool) Don't send notification to the listener
B_HTTPOPT_AUTOREFERER, B_HTTPOPT_AUTOREFERER,
// (bool) Automatically set the Referer header // (bool) Automatically set the Referer header
@@ -156,7 +156,7 @@ enum {
// (string) Authentication password // (string) Authentication password
B_HTTPOPT_AUTHMETHOD, B_HTTPOPT_AUTHMETHOD,
// (int) Allowed authentication methods (see BHttpAuthenticationMethod) // (int) Allowed authentication methods (see BHttpAuthenticationMethod)
B_HTTPOPT__OPT_NUM B_HTTPOPT__OPT_NUM
}; };
@@ -179,7 +179,7 @@ enum http_status_code {
B_HTTP_STATUS_CONTINUE = B_HTTP_STATUS__INFORMATIONAL_BASE, B_HTTP_STATUS_CONTINUE = B_HTTP_STATUS__INFORMATIONAL_BASE,
B_HTTP_STATUS_SWITCHING_PROTOCOLS, B_HTTP_STATUS_SWITCHING_PROTOCOLS,
B_HTTP_STATUS__INFORMATIONAL_END, B_HTTP_STATUS__INFORMATIONAL_END,
// Success status codes // Success status codes
B_HTTP_STATUS__SUCCESS_BASE = 200, B_HTTP_STATUS__SUCCESS_BASE = 200,
B_HTTP_STATUS_OK = B_HTTP_STATUS__SUCCESS_BASE, B_HTTP_STATUS_OK = B_HTTP_STATUS__SUCCESS_BASE,
@@ -190,7 +190,7 @@ enum http_status_code {
B_HTTP_STATUS_RESET_CONTENT, B_HTTP_STATUS_RESET_CONTENT,
B_HTTP_STATUS_PARTIAL_CONTENT, B_HTTP_STATUS_PARTIAL_CONTENT,
B_HTTP_STATUS__SUCCESS_END, B_HTTP_STATUS__SUCCESS_END,
// Redirection status codes // Redirection status codes
B_HTTP_STATUS__REDIRECTION_BASE = 300, B_HTTP_STATUS__REDIRECTION_BASE = 300,
B_HTTP_STATUS_MULTIPLE_CHOICE = B_HTTP_STATUS__REDIRECTION_BASE, B_HTTP_STATUS_MULTIPLE_CHOICE = B_HTTP_STATUS__REDIRECTION_BASE,
@@ -201,7 +201,7 @@ enum http_status_code {
B_HTTP_STATUS_USE_PROXY, B_HTTP_STATUS_USE_PROXY,
B_HTTP_STATUS_TEMPORARY_REDIRECT, B_HTTP_STATUS_TEMPORARY_REDIRECT,
B_HTTP_STATUS__REDIRECTION_END, B_HTTP_STATUS__REDIRECTION_END,
// Client error status codes // Client error status codes
B_HTTP_STATUS__CLIENT_ERROR_BASE = 400, B_HTTP_STATUS__CLIENT_ERROR_BASE = 400,
B_HTTP_STATUS_BAD_REQUEST = B_HTTP_STATUS__CLIENT_ERROR_BASE, B_HTTP_STATUS_BAD_REQUEST = B_HTTP_STATUS__CLIENT_ERROR_BASE,
@@ -223,7 +223,7 @@ enum http_status_code {
B_HTTP_STATUS_REQUESTED_RANGE_NOT_SATISFIABLE, B_HTTP_STATUS_REQUESTED_RANGE_NOT_SATISFIABLE,
B_HTTP_STATUS_EXPECTATION_FAILED, B_HTTP_STATUS_EXPECTATION_FAILED,
B_HTTP_STATUS__CLIENT_ERROR_END, B_HTTP_STATUS__CLIENT_ERROR_END,
// Server error status codes // Server error status codes
B_HTTP_STATUS__SERVER_ERROR_BASE = 500, B_HTTP_STATUS__SERVER_ERROR_BASE = 500,
B_HTTP_STATUS_INTERNAL_SERVER_ERROR = B_HTTP_STATUS__SERVER_ERROR_BASE, B_HTTP_STATUS_INTERNAL_SERVER_ERROR = B_HTTP_STATUS__SERVER_ERROR_BASE,
+13 -12
View File
@@ -22,36 +22,34 @@ enum {
class BUrlRequest { class BUrlRequest {
public: public:
BUrlRequest(const BUrl& url, BUrlRequest(const BUrl& url,
BUrlProtocolListener* listener); BUrlProtocolListener* listener = NULL,
BUrlRequest(const BUrl& url); BUrlContext* context = NULL);
BUrlRequest(const BUrlRequest& other); BUrlRequest(const BUrlRequest& other);
virtual ~BUrlRequest() { }; virtual ~BUrlRequest();
// Request parameters modification // Request parameters modification
status_t SetUrl(const BUrl& url); status_t SetUrl(const BUrl& url);
void SetContext(BUrlContext* context); void SetContext(BUrlContext* context);
void SetProtocolListener( void SetProtocolListener(
BUrlProtocolListener* listener); BUrlProtocolListener* listener);
bool SetProtocolOption(int32 option, bool SetProtocolOption(int32 option,
void* value); void* value);
// Request parameters access // Request parameters access
const BUrlProtocol* Protocol(); const BUrlProtocol* Protocol();
const BUrlResult& Result(); const BUrlResult& Result();
const BUrl& Url(); const BUrl& Url();
// Request control // Request control
status_t Identify(); virtual status_t Start();
virtual status_t Perform();
// TODO: Rename to Run() perhaps? "Perform" is used for FBC stuff.
virtual status_t Pause(); virtual status_t Pause();
virtual status_t Resume(); virtual status_t Resume();
virtual status_t Abort(); virtual status_t Abort();
// Request informations // Request informations
virtual bool InitCheck() const; virtual status_t InitCheck() const;
bool IsRunning() const; bool IsRunning() const;
status_t Status() const; status_t Status() const;
// Overloaded members // Overloaded members
BUrlRequest& operator=(const BUrlRequest& other); BUrlRequest& operator=(const BUrlRequest& other);
@@ -62,7 +60,10 @@ protected:
BUrlResult fResult; BUrlResult fResult;
BUrlContext* fContext; BUrlContext* fContext;
BUrl fUrl; BUrl fUrl;
bool fReady; status_t fInitStatus;
private:
status_t _SetupProtocol();
}; };
#endif // _B_URL_REQUEST_H_ #endif // _B_URL_REQUEST_H_
+27 -27
View File
@@ -28,9 +28,9 @@ static const char* kProtocolThreadStrStatus[B_PROT_THREAD_STATUS__END+1]
BUrlProtocol::BUrlProtocol(const BUrl& url, BUrlProtocolListener* listener, BUrlProtocol::BUrlProtocol(const BUrl& url, BUrlProtocolListener* listener,
BUrlContext* context, BUrlResult* result, const char* threadName, BUrlContext* context, BUrlResult* result, const char* threadName,
const char* protocolName) const char* protocolName)
: :
fUrl(url), fUrl(url),
fResult(result), fResult(result),
fContext(context), fContext(context),
@@ -61,20 +61,20 @@ BUrlProtocol::Run()
"[urlProtocol=%p]!\n", this)); "[urlProtocol=%p]!\n", this));
return fThreadId; return fThreadId;
} }
fThreadId = spawn_thread(BUrlProtocol::_ThreadEntry, fThreadName, fThreadId = spawn_thread(BUrlProtocol::_ThreadEntry, fThreadName,
B_NORMAL_PRIORITY, this); B_NORMAL_PRIORITY, this);
if (fThreadId < B_OK) if (fThreadId < B_OK)
return fThreadId; return fThreadId;
status_t launchErr = resume_thread(fThreadId); status_t launchErr = resume_thread(fThreadId);
if (launchErr < B_OK) { if (launchErr < B_OK) {
PRINT(("BUrlProtocol::Run() : Failed to resume thread %ld\n", PRINT(("BUrlProtocol::Run() : Failed to resume thread %ld\n",
fThreadId)); fThreadId));
return launchErr; return launchErr;
} }
fRunning = true; fRunning = true;
return fThreadId; return fThreadId;
} }
@@ -101,11 +101,11 @@ BUrlProtocol::Stop()
{ {
if (!fRunning) if (!fRunning)
return B_ERROR; return B_ERROR;
status_t threadStatus = B_OK; status_t threadStatus = B_OK;
fQuit = true; fQuit = true;
wait_for_thread(fThreadId, &threadStatus); wait_for_thread(fThreadId, &threadStatus);
return threadStatus; return threadStatus;
} }
@@ -119,7 +119,7 @@ BUrlProtocol::SetUrl(const BUrl& url)
// We should avoid to change URL while the thread is running ... // We should avoid to change URL while the thread is running ...
if (IsRunning()) if (IsRunning())
return B_ERROR; return B_ERROR;
fUrl = url; fUrl = url;
return B_OK; return B_OK;
} }
@@ -130,7 +130,7 @@ BUrlProtocol::SetResult(BUrlResult* result)
{ {
if (IsRunning()) if (IsRunning())
return B_ERROR; return B_ERROR;
fResult = result; fResult = result;
return B_OK; return B_OK;
} }
@@ -138,10 +138,10 @@ BUrlProtocol::SetResult(BUrlResult* result)
status_t status_t
BUrlProtocol::SetContext(BUrlContext* context) BUrlProtocol::SetContext(BUrlContext* context)
{ {
if (IsRunning()) if (IsRunning())
return B_ERROR; return B_ERROR;
fContext = context; fContext = context;
return B_OK; return B_OK;
} }
@@ -152,7 +152,7 @@ BUrlProtocol::SetListener(BUrlProtocolListener* listener)
{ {
if (IsRunning()) if (IsRunning())
return B_ERROR; return B_ERROR;
fListener = listener; fListener = listener;
return B_OK; return B_OK;
} }
@@ -226,23 +226,23 @@ BUrlProtocol::StatusString(status_t threadStatus) const
// #pragma mark Thread management // #pragma mark Thread management
/*static*/ int32 /*static*/ int32
BUrlProtocol::_ThreadEntry(void* arg) BUrlProtocol::_ThreadEntry(void* arg)
{ {
BUrlProtocol* urlProtocol = reinterpret_cast<BUrlProtocol*>(arg); BUrlProtocol* urlProtocol = reinterpret_cast<BUrlProtocol*>(arg);
urlProtocol->fThreadStatus = B_PROT_RUNNING; urlProtocol->fThreadStatus = B_PROT_RUNNING;
status_t protocolLoopExitStatus = urlProtocol->_ProtocolLoop(); status_t protocolLoopExitStatus = urlProtocol->_ProtocolLoop();
urlProtocol->fRunning = false; urlProtocol->fRunning = false;
urlProtocol->fThreadStatus = protocolLoopExitStatus; urlProtocol->fThreadStatus = protocolLoopExitStatus;
if (urlProtocol->fListener != NULL) if (urlProtocol->fListener != NULL)
urlProtocol->fListener->RequestCompleted(urlProtocol, urlProtocol->fListener->RequestCompleted(urlProtocol,
protocolLoopExitStatus == B_PROT_SUCCESS); protocolLoopExitStatus == B_PROT_SUCCESS);
return B_OK; return B_OK;
} }
@@ -253,13 +253,13 @@ BUrlProtocol::_ProtocolLoop()
// Dummy _ProtocolLoop // Dummy _ProtocolLoop
while (!fQuit) while (!fQuit)
snooze(1000); snooze(1000);
return B_PROT_SUCCESS; return B_PROT_SUCCESS;
} }
void void
BUrlProtocol::_EmitDebug(BUrlProtocolDebugMessage type, BUrlProtocol::_EmitDebug(BUrlProtocolDebugMessage type,
const char* format, ...) const char* format, ...)
{ {
if (fListener == NULL) if (fListener == NULL)
@@ -267,7 +267,7 @@ BUrlProtocol::_EmitDebug(BUrlProtocolDebugMessage type,
va_list arguments; va_list arguments;
va_start(arguments, format); va_start(arguments, format);
char debugMsg[256]; char debugMsg[256];
vsnprintf(debugMsg, 256, format, arguments); vsnprintf(debugMsg, 256, format, arguments);
fListener->DebugMessage(this, type, debugMsg); fListener->DebugMessage(this, type, debugMsg);
@@ -275,7 +275,7 @@ BUrlProtocol::_EmitDebug(BUrlProtocolDebugMessage type,
} }
BMallocIO& BMallocIO&
BUrlProtocol::_ResultRawData() BUrlProtocol::_ResultRawData()
{ {
return fResult->fRawData; return fResult->fRawData;
+177 -201
View File
@@ -31,10 +31,10 @@ static const char* kHttpProtocolThreadStrStatus[
}; };
BUrlProtocolHttp::BUrlProtocolHttp(BUrl& url, bool ssl, BUrlProtocolHttp::BUrlProtocolHttp(BUrl& url, bool ssl,
const char *protocolName, BUrlProtocolListener* listener, const char* protocolName, BUrlProtocolListener* listener,
BUrlContext* context, BUrlResult* result) BUrlContext* context, BUrlResult* result)
: :
BUrlProtocol(url, listener, context, result, "BUrlProtocol.HTTP", protocolName), BUrlProtocol(url, listener, context, result, "BUrlProtocol.HTTP", protocolName),
fSSL(ssl), fSSL(ssl),
fRequestMethod(B_HTTP_GET), fRequestMethod(B_HTTP_GET),
@@ -45,7 +45,6 @@ BUrlProtocolHttp::BUrlProtocolHttp(BUrl& url, bool ssl,
fSocket = new BSecureSocket(); fSocket = new BSecureSocket();
else else
fSocket = new BSocket(); fSocket = new BSocket();
} }
@@ -59,67 +58,67 @@ status_t
BUrlProtocolHttp::SetOption(uint32 name, void* value) BUrlProtocolHttp::SetOption(uint32 name, void* value)
{ {
BUrlProtocolOption option(value); BUrlProtocolOption option(value);
switch (name) { switch (name) {
case B_HTTPOPT_METHOD: case B_HTTPOPT_METHOD:
fRequestMethod = option.Int8(); fRequestMethod = option.Int8();
break; break;
case B_HTTPOPT_FOLLOWLOCATION: case B_HTTPOPT_FOLLOWLOCATION:
fOptFollowLocation = option.Bool(); fOptFollowLocation = option.Bool();
break; break;
case B_HTTPOPT_MAXREDIRS: case B_HTTPOPT_MAXREDIRS:
fOptMaxRedirs = option.Int8(); fOptMaxRedirs = option.Int8();
break; break;
case B_HTTPOPT_REFERER: case B_HTTPOPT_REFERER:
fOptReferer = option.String(); fOptReferer = option.String();
break; break;
case B_HTTPOPT_USERAGENT: case B_HTTPOPT_USERAGENT:
fOptUserAgent = option.String(); fOptUserAgent = option.String();
break; break;
case B_HTTPOPT_HEADERS: case B_HTTPOPT_HEADERS:
fOptHeaders = reinterpret_cast<BHttpHeaders*>(option.Pointer()); fOptHeaders = reinterpret_cast<BHttpHeaders*>(option.Pointer());
break; break;
case B_HTTPOPT_DISCARD_DATA: case B_HTTPOPT_DISCARD_DATA:
fOptDiscardData = option.Bool(); fOptDiscardData = option.Bool();
break; break;
case B_HTTPOPT_DISABLE_LISTENER: case B_HTTPOPT_DISABLE_LISTENER:
fOptDisableListener = option.Bool(); fOptDisableListener = option.Bool();
break; break;
case B_HTTPOPT_AUTOREFERER: case B_HTTPOPT_AUTOREFERER:
fOptAutoReferer = option.Bool(); fOptAutoReferer = option.Bool();
break; break;
case B_HTTPOPT_POSTFIELDS: case B_HTTPOPT_POSTFIELDS:
fOptPostFields = reinterpret_cast<BHttpForm*>(option.Pointer()); fOptPostFields = reinterpret_cast<BHttpForm*>(option.Pointer());
if (fOptPostFields != NULL) if (fOptPostFields != NULL)
fRequestMethod = B_HTTP_POST; fRequestMethod = B_HTTP_POST;
break; break;
case B_HTTPOPT_INPUTDATA: case B_HTTPOPT_INPUTDATA:
fOptInputData = reinterpret_cast<BDataIO*>(option.Pointer()); fOptInputData = reinterpret_cast<BDataIO*>(option.Pointer());
break; break;
case B_HTTPOPT_AUTHUSERNAME: case B_HTTPOPT_AUTHUSERNAME:
fOptUsername = option.String(); fOptUsername = option.String();
break; break;
case B_HTTPOPT_AUTHPASSWORD: case B_HTTPOPT_AUTHPASSWORD:
fOptPassword = option.String(); fOptPassword = option.String();
break; break;
default: default:
return B_ERROR; return B_ERROR;
} }
return B_OK; return B_OK;
} }
@@ -177,7 +176,7 @@ BUrlProtocolHttp::StatusCodeClass(int16 code)
return B_HTTP_STATUS_CLASS_CLIENT_ERROR; return B_HTTP_STATUS_CLASS_CLIENT_ERROR;
else if (BUrlProtocolHttp::IsServerErrorStatusCode(code)) else if (BUrlProtocolHttp::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;
} }
@@ -190,11 +189,11 @@ BUrlProtocolHttp::StatusString(status_t threadStatus) const
else if (threadStatus >= B_PROT_HTTP_THREAD_STATUS__END) else if (threadStatus >= B_PROT_HTTP_THREAD_STATUS__END)
return BUrlProtocol::StatusString(-1); return BUrlProtocol::StatusString(-1);
else else
return kHttpProtocolThreadStrStatus[threadStatus return kHttpProtocolThreadStrStatus[threadStatus
- B_PROT_THREAD_STATUS__END]; - B_PROT_THREAD_STATUS__END];
} }
void void
BUrlProtocolHttp::_ResetOptions() BUrlProtocolHttp::_ResetOptions()
{ {
@@ -204,7 +203,7 @@ BUrlProtocolHttp::_ResetOptions()
fOptUserAgent = "Services Kit (Haiku)"; fOptUserAgent = "Services Kit (Haiku)";
fOptUsername = ""; fOptUsername = "";
fOptPassword = ""; fOptPassword = "";
fOptAuthMethods = B_HTTP_AUTHENTICATION_BASIC | B_HTTP_AUTHENTICATION_DIGEST fOptAuthMethods = B_HTTP_AUTHENTICATION_BASIC | B_HTTP_AUTHENTICATION_DIGEST
| B_HTTP_AUTHENTICATION_IE_DIGEST; | B_HTTP_AUTHENTICATION_IE_DIGEST;
fOptHeaders = NULL; fOptHeaders = NULL;
fOptPostFields = NULL; fOptPostFields = NULL;
@@ -217,16 +216,16 @@ BUrlProtocolHttp::_ResetOptions()
#include <stdio.h> #include <stdio.h>
status_t status_t
BUrlProtocolHttp::_ProtocolLoop() BUrlProtocolHttp::_ProtocolLoop()
{ {
printf("UHP[%p]::{Loop} %s\n", this, fUrl.UrlString().String()); printf("UHP[%p]::{Loop} %s\n", this, fUrl.UrlString().String());
// Initialize the request redirection loop // Initialize the request redirection loop
int8 maxRedirs = fOptMaxRedirs; int8 maxRedirs = fOptMaxRedirs;
bool newRequest; bool newRequest;
do { do {
newRequest = false; newRequest = false;
// Result reset // Result reset
fOutputBuffer.Truncate(0, true); fOutputBuffer.Truncate(0, true);
fOutputHeaders.Clear(); fOutputHeaders.Clear();
@@ -234,61 +233,61 @@ BUrlProtocolHttp::_ProtocolLoop()
_ResultHeaders().Clear(); _ResultHeaders().Clear();
_ResultRawData().Seek(SEEK_SET, 0); _ResultRawData().Seek(SEEK_SET, 0);
_ResultRawData().SetSize(0); _ResultRawData().SetSize(0);
if (!_ResolveHostName()) { if (!_ResolveHostName()) {
_EmitDebug(B_URL_PROTOCOL_DEBUG_ERROR, _EmitDebug(B_URL_PROTOCOL_DEBUG_ERROR,
"Unable to resolve hostname, aborting."); "Unable to resolve hostname, aborting.");
return B_PROT_CANT_RESOLVE_HOSTNAME; return B_PROT_CANT_RESOLVE_HOSTNAME;
} }
_CreateRequest(); _CreateRequest();
_AddHeaders(); _AddHeaders();
_AddOutputBufferLine(""); _AddOutputBufferLine("");
status_t requestStatus = _MakeRequest(); status_t requestStatus = _MakeRequest();
if (requestStatus != B_PROT_SUCCESS) if (requestStatus != B_PROT_SUCCESS)
return requestStatus; return requestStatus;
// Prepare the referer for the next request if needed // Prepare the referer for the next request if needed
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
break; break;
case B_HTTP_STATUS_CLASS_SUCCESS: case B_HTTP_STATUS_CLASS_SUCCESS:
break; break;
case B_HTTP_STATUS_CLASS_REDIRECTION: case B_HTTP_STATUS_CLASS_REDIRECTION:
// Redirection has been explicitly disabled // Redirection has been explicitly disabled
if (!fOptFollowLocation) if (!fOptFollowLocation)
break; break;
// 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
if (locationUrl[0] == '/') if (locationUrl[0] == '/')
fUrl.SetPath(locationUrl); fUrl.SetPath(locationUrl);
// URI // URI
else else
fUrl.SetUrlString(locationUrl); fUrl.SetUrlString(locationUrl);
if (--maxRedirs > 0) { if (--maxRedirs > 0) {
newRequest = true; newRequest = true;
_EmitDebug(B_URL_PROTOCOL_DEBUG_TEXT, _EmitDebug(B_URL_PROTOCOL_DEBUG_TEXT,
"Following: %s\n", "Following: %s\n",
fUrl.UrlString().String()); fUrl.UrlString().String());
} }
} }
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:
@@ -296,7 +295,7 @@ BUrlProtocolHttp::_ProtocolLoop()
newRequest = false; newRequest = false;
break; break;
} }
newRequest = false; newRequest = false;
if (fOptUsername.Length() > 0 if (fOptUsername.Length() > 0
&& fAuthentication.Initialize(fHeaders["WWW-Authenticate"]) && fAuthentication.Initialize(fHeaders["WWW-Authenticate"])
@@ -308,21 +307,20 @@ BUrlProtocolHttp::_ProtocolLoop()
break; break;
} }
break; break;
case B_HTTP_STATUS_CLASS_SERVER_ERROR: case B_HTTP_STATUS_CLASS_SERVER_ERROR:
break; break;
default: default:
case B_HTTP_STATUS_CLASS_INVALID: case B_HTTP_STATUS_CLASS_INVALID:
break; break;
} }
} while (newRequest); } while (newRequest);
_EmitDebug(B_URL_PROTOCOL_DEBUG_TEXT, _EmitDebug(B_URL_PROTOCOL_DEBUG_TEXT,
"%ld headers and %ld bytes of data remaining", "%ld headers and %ld bytes of data remaining",
fHeaders.CountHeaders(), fHeaders.CountHeaders(), fInputBuffer.Size());
fInputBuffer.Size());
if (fResult->StatusCode() == 404) if (fResult->StatusCode() == 404)
return B_PROT_HTTP_NOT_FOUND; return B_PROT_HTTP_NOT_FOUND;
@@ -335,27 +333,23 @@ BUrlProtocolHttp::_ResolveHostName()
{ {
_EmitDebug(B_URL_PROTOCOL_DEBUG_TEXT, "Resolving %s", _EmitDebug(B_URL_PROTOCOL_DEBUG_TEXT, "Resolving %s",
fUrl.UrlString().String()); fUrl.UrlString().String());
if (fUrl.HasPort()) if (fUrl.HasPort())
fRemoteAddr = BNetworkAddress(fUrl.Host(), fUrl.Port()); fRemoteAddr = BNetworkAddress(fUrl.Host(), fUrl.Port());
else { else {
if (fSSL) fRemoteAddr = BNetworkAddress(fUrl.Host(), fSSL ? 443 : 80);
fRemoteAddr = BNetworkAddress(fUrl.Host(), 443);
else
fRemoteAddr = BNetworkAddress(fUrl.Host(), 80);
} }
if (fRemoteAddr.InitCheck() != B_OK) if (fRemoteAddr.InitCheck() != B_OK)
return false; return false;
//! ProtocolHook:HostnameResolved //! ProtocolHook:HostnameResolved
if (fListener != NULL) if (fListener != NULL)
fListener->HostnameResolved(this, fListener->HostnameResolved(this, fRemoteAddr.ToString().String());
const_cast<const char*>(fRemoteAddr.ToString().String()));
_EmitDebug(B_URL_PROTOCOL_DEBUG_TEXT, "Hostname resolved to: %s",
_EmitDebug(B_URL_PROTOCOL_DEBUG_TEXT, "Hostname resolved to: %s", fRemoteAddr.ToString().String());
fRemoteAddr.ToString().String());
return true; return true;
} }
@@ -363,58 +357,58 @@ BUrlProtocolHttp::_ResolveHostName()
status_t status_t
BUrlProtocolHttp::_MakeRequest() BUrlProtocolHttp::_MakeRequest()
{ {
_EmitDebug(B_URL_PROTOCOL_DEBUG_TEXT, "Connection to %s.", _EmitDebug(B_URL_PROTOCOL_DEBUG_TEXT, "Connection to %s.",
fUrl.Authority().String()); fUrl.Authority().String());
status_t connectError = fSocket->Connect(fRemoteAddr); status_t connectError = fSocket->Connect(fRemoteAddr);
if (connectError != B_OK) { if (connectError != B_OK) {
_EmitDebug(B_URL_PROTOCOL_DEBUG_ERROR, "Socket connection error."); _EmitDebug(B_URL_PROTOCOL_DEBUG_ERROR, "Socket connection error.");
return B_PROT_CONNECTION_FAILED; return B_PROT_CONNECTION_FAILED;
} }
//! ProtocolHook:ConnectionOpened //! ProtocolHook:ConnectionOpened
if (fListener != NULL) if (fListener != NULL)
fListener->ConnectionOpened(this); fListener->ConnectionOpened(this);
_EmitDebug(B_URL_PROTOCOL_DEBUG_TEXT, "Connection opened."); _EmitDebug(B_URL_PROTOCOL_DEBUG_TEXT, "Connection opened.");
_EmitDebug(B_URL_PROTOCOL_DEBUG_TEXT, "Sending request (size=%d)", _EmitDebug(B_URL_PROTOCOL_DEBUG_TEXT, "Sending request (size=%d)",
fOutputBuffer.Length()); fOutputBuffer.Length());
fSocket->Write(fOutputBuffer.String(), fOutputBuffer.Length()); fSocket->Write(fOutputBuffer.String(), fOutputBuffer.Length());
fOutputBuffer.Truncate(0); fOutputBuffer.Truncate(0);
_EmitDebug(B_URL_PROTOCOL_DEBUG_TEXT, "Request sent."); _EmitDebug(B_URL_PROTOCOL_DEBUG_TEXT, "Request sent.");
if (fRequestMethod == B_HTTP_POST && fOptPostFields != NULL) { if (fRequestMethod == B_HTTP_POST && fOptPostFields != NULL) {
if (fOptPostFields->GetFormType() != B_HTTP_FORM_MULTIPART) { if (fOptPostFields->GetFormType() != B_HTTP_FORM_MULTIPART) {
fOutputBuffer = fOptPostFields->RawData(); fOutputBuffer = fOptPostFields->RawData();
_EmitDebug(B_URL_PROTOCOL_DEBUG_TRANSFER_OUT, _EmitDebug(B_URL_PROTOCOL_DEBUG_TRANSFER_OUT,
fOutputBuffer.String()); fOutputBuffer.String());
fSocket->Write(fOutputBuffer.String(), fOutputBuffer.Length()); fSocket->Write(fOutputBuffer.String(), fOutputBuffer.Length());
} else { } else {
for (BHttpForm::Iterator it = fOptPostFields->GetIterator(); for (BHttpForm::Iterator it = fOptPostFields->GetIterator();
const BHttpFormData* currentField = it.Next(); const BHttpFormData* currentField = it.Next();
) { ) {
_EmitDebug(B_URL_PROTOCOL_DEBUG_TRANSFER_OUT, _EmitDebug(B_URL_PROTOCOL_DEBUG_TRANSFER_OUT,
it.MultipartHeader().String()); it.MultipartHeader().String());
fSocket->Write(it.MultipartHeader().String(), fSocket->Write(it.MultipartHeader().String(),
it.MultipartHeader().Length()); it.MultipartHeader().Length());
switch (currentField->Type()) { switch (currentField->Type()) {
case B_HTTPFORM_UNKNOWN: case B_HTTPFORM_UNKNOWN:
ASSERT(0); ASSERT(0);
break; break;
case B_HTTPFORM_STRING: case B_HTTPFORM_STRING:
fSocket->Write(currentField->String().String(), fSocket->Write(currentField->String().String(),
currentField->String().Length()); currentField->String().Length());
break; break;
case B_HTTPFORM_FILE: case B_HTTPFORM_FILE:
{ {
BFile upFile(currentField->File().Path(), BFile upFile(currentField->File().Path(),
B_READ_ONLY); B_READ_ONLY);
char readBuffer[1024]; char readBuffer[1024];
ssize_t readSize; ssize_t readSize;
readSize = upFile.Read(readBuffer, 1024); readSize = upFile.Read(readBuffer, 1024);
while (readSize > 0) { while (readSize > 0) {
@@ -423,45 +417,45 @@ BUrlProtocolHttp::_MakeRequest()
} }
} }
break; break;
case B_HTTPFORM_BUFFER: case B_HTTPFORM_BUFFER:
fSocket->Write(currentField->Buffer(), fSocket->Write(currentField->Buffer(),
currentField->BufferSize()); currentField->BufferSize());
break; break;
} }
fSocket->Write("\r\n", 2); fSocket->Write("\r\n", 2);
} }
fSocket->Write(fOptPostFields->GetMultipartFooter().String(), fSocket->Write(fOptPostFields->GetMultipartFooter().String(),
fOptPostFields->GetMultipartFooter().Length()); fOptPostFields->GetMultipartFooter().Length());
} }
} else if ((fRequestMethod == B_HTTP_POST || fRequestMethod == B_HTTP_PUT) } else if ((fRequestMethod == B_HTTP_POST || fRequestMethod == B_HTTP_PUT)
&& fOptInputData != NULL) { && fOptInputData != NULL) {
char outputTempBuffer[1024]; char outputTempBuffer[1024];
ssize_t read = 0; ssize_t read = 0;
while (read != -1) { while (read != -1) {
read = fOptInputData->Read(outputTempBuffer, 1024); read = fOptInputData->Read(outputTempBuffer, 1024);
if (read > 0) { if (read > 0) {
char hexSize[16]; char hexSize[16];
size_t hexLength = sprintf(hexSize, "%ld", read); 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);
} }
} }
fSocket->Write("0\r\n\r\n", 5); fSocket->Write("0\r\n\r\n", 5);
} }
fOutputBuffer.Truncate(0, true); fOutputBuffer.Truncate(0, true);
fStatusReceived = false; fStatusReceived = false;
fHeadersReceived = false; fHeadersReceived = false;
// Receive loop // Receive loop
bool receiveEnd = false; bool receiveEnd = false;
bool parseEnd = false; bool parseEnd = false;
@@ -473,38 +467,38 @@ BUrlProtocolHttp::_MakeRequest()
ssize_t bytesTotal = 0; ssize_t bytesTotal = 0;
char* inputTempBuffer = NULL; char* inputTempBuffer = NULL;
fQuit = false; fQuit = false;
while (!fQuit && !(receiveEnd && parseEnd)) { while (!fQuit && !(receiveEnd && parseEnd)) {
if (!receiveEnd) { if (!receiveEnd) {
fSocket->WaitForReadable(); fSocket->WaitForReadable();
BNetBuffer chunk(receiveBufferSize); BNetBuffer chunk(receiveBufferSize);
bytesRead = fSocket->Read(chunk.Data(), receiveBufferSize); bytesRead = fSocket->Read(chunk.Data(), receiveBufferSize);
if (bytesRead < 0) { if (bytesRead < 0) {
readError = true; readError = true;
fQuit = true; fQuit = true;
continue; continue;
} else if (bytesRead == 0) } else if (bytesRead == 0)
receiveEnd = true; receiveEnd = true;
fInputBuffer.AppendData(chunk.Data(), bytesRead); fInputBuffer.AppendData(chunk.Data(), bytesRead);
} }
else else
bytesRead = 0; bytesRead = 0;
if (!fStatusReceived) { if (!fStatusReceived) {
_ParseStatus(); _ParseStatus();
//! ProtocolHook:ResponseStarted //! ProtocolHook:ResponseStarted
if (fStatusReceived && fListener != NULL) if (fStatusReceived && fListener != NULL)
fListener->ResponseStarted(this); fListener->ResponseStarted(this);
} else if (!fHeadersReceived) { } else if (!fHeadersReceived) {
_ParseHeaders(); _ParseHeaders();
if (fHeadersReceived) { if (fHeadersReceived) {
receiveBufferSize = kHttpProtocolReceiveBufferSize; receiveBufferSize = kHttpProtocolReceiveBufferSize;
_ResultHeaders() = fHeaders; _ResultHeaders() = fHeaders;
//! ProtocolHook:HeadersReceived //! ProtocolHook:HeadersReceived
if (fListener != NULL) if (fListener != NULL)
fListener->HeadersReceived(this); fListener->HeadersReceived(this);
@@ -516,10 +510,10 @@ BUrlProtocolHttp::_MakeRequest()
} }
} }
} }
if (BString(fHeaders["Transfer-Encoding"]) == "chunked") if (BString(fHeaders["Transfer-Encoding"]) == "chunked")
readByChunks = true; readByChunks = true;
int32 index = fHeaders.HasHeader("Content-Length"); int32 index = fHeaders.HasHeader("Content-Length");
if (index != B_ERROR) if (index != B_ERROR)
bytesTotal = atoi(fHeaders.HeaderAt(index).Value()); bytesTotal = atoi(fHeaders.HeaderAt(index).Value());
@@ -531,7 +525,7 @@ BUrlProtocolHttp::_MakeRequest()
// chunk in buffer before handling it // chunk in buffer before handling it
if (readByChunks) { if (readByChunks) {
_CopyChunkInBuffer(&inputTempBuffer, &bytesRead); _CopyChunkInBuffer(&inputTempBuffer, &bytesRead);
// A chunk of 0 bytes indicates the end of the chunked transfer // A chunk of 0 bytes indicates the end of the chunked transfer
if (bytesRead == 0) { if (bytesRead == 0) {
receiveEnd = true; receiveEnd = true;
@@ -539,50 +533,50 @@ BUrlProtocolHttp::_MakeRequest()
} }
else { else {
bytesRead = fInputBuffer.Size(); bytesRead = fInputBuffer.Size();
if (bytesRead > 0) { if (bytesRead > 0) {
inputTempBuffer = new char[bytesRead]; inputTempBuffer = new char[bytesRead];
fInputBuffer.RemoveData(inputTempBuffer, bytesRead); fInputBuffer.RemoveData(inputTempBuffer, bytesRead);
} }
} }
if (bytesRead > 0) { if (bytesRead > 0) {
bytesReceived += bytesRead; bytesReceived += bytesRead;
_EmitDebug(B_URL_PROTOCOL_DEBUG_TRANSFER_IN, "%d bytes", _EmitDebug(B_URL_PROTOCOL_DEBUG_TRANSFER_IN, "%d bytes",
bytesRead); bytesRead);
if (fListener != NULL) { if (fListener != NULL) {
fListener->DataReceived(this, inputTempBuffer, bytesRead); fListener->DataReceived(this, inputTempBuffer, bytesRead);
fListener->DownloadProgress(this, bytesReceived, fListener->DownloadProgress(this, bytesReceived,
bytesTotal); bytesTotal);
} }
ssize_t dataWrite = _ResultRawData().Write(inputTempBuffer, ssize_t dataWrite = _ResultRawData().Write(inputTempBuffer,
bytesRead); bytesRead);
if (dataWrite != bytesRead) { if (dataWrite != bytesRead) {
_EmitDebug(B_URL_PROTOCOL_DEBUG_ERROR, _EmitDebug(B_URL_PROTOCOL_DEBUG_ERROR,
"Unable to write %dbytes of data (%d).", bytesRead, "Unable to write %dbytes of data (%d).", bytesRead,
dataWrite); dataWrite);
return B_PROT_NO_MEMORY; return B_PROT_NO_MEMORY;
} }
if (bytesTotal > 0 && bytesReceived >= bytesTotal) if (bytesTotal > 0 && bytesReceived >= bytesTotal)
receiveEnd = true; receiveEnd = true;
delete[] inputTempBuffer; delete[] inputTempBuffer;
} }
} }
parseEnd = (fInputBuffer.Size() == 0); parseEnd = (fInputBuffer.Size() == 0);
} }
fSocket->Disconnect(); fSocket->Disconnect();
if (readError) if (readError)
return B_PROT_READ_FAILED; return B_PROT_READ_FAILED;
return fQuit?B_PROT_ABORTED:B_PROT_SUCCESS; return fQuit ? B_PROT_ABORTED : B_PROT_SUCCESS;
} }
@@ -591,23 +585,23 @@ BUrlProtocolHttp::_GetLine(BString& destString)
{ {
// Find a complete line in inputBuffer // Find a complete line in inputBuffer
uint32 characterIndex = 0; uint32 characterIndex = 0;
while ((characterIndex < fInputBuffer.Size()) while ((characterIndex < fInputBuffer.Size())
&& ((fInputBuffer.Data())[characterIndex] != '\n')) && ((fInputBuffer.Data())[characterIndex] != '\n'))
characterIndex++; characterIndex++;
if (characterIndex == fInputBuffer.Size()) if (characterIndex == fInputBuffer.Size())
return B_ERROR; return B_ERROR;
char* temporaryBuffer = new(std::nothrow) char[characterIndex + 1]; char* temporaryBuffer = new(std::nothrow) char[characterIndex + 1];
fInputBuffer.RemoveData(temporaryBuffer, characterIndex + 1); fInputBuffer.RemoveData(temporaryBuffer, characterIndex + 1);
// Strip end-of-line character(s) // Strip end-of-line character(s)
if (temporaryBuffer[characterIndex-1] == '\r') if (temporaryBuffer[characterIndex-1] == '\r')
destString.SetTo(temporaryBuffer, characterIndex - 1); destString.SetTo(temporaryBuffer, characterIndex - 1);
else else
destString.SetTo(temporaryBuffer, characterIndex); destString.SetTo(temporaryBuffer, characterIndex);
delete[] temporaryBuffer; delete[] temporaryBuffer;
return B_OK; return B_OK;
} }
@@ -624,19 +618,19 @@ BUrlProtocolHttp::_ParseStatus()
BString statusLine; BString statusLine;
if (_GetLine(statusLine) == B_ERROR) if (_GetLine(statusLine) == B_ERROR)
return; return;
if (statusLine.CountChars() < 12) if (statusLine.CountChars() < 12)
return; return;
fStatusReceived = true; fStatusReceived = true;
BString statusCodeStr; BString statusCodeStr;
BString statusText; BString statusText;
statusLine.CopyInto(statusCodeStr, 9, 3); statusLine.CopyInto(statusCodeStr, 9, 3);
_SetResultStatusCode(atoi(statusCodeStr.String())); _SetResultStatusCode(atoi(statusCodeStr.String()));
statusLine.CopyInto(_ResultStatusText(), 13, statusLine.Length() - 13); statusLine.CopyInto(_ResultStatusText(), 13, statusLine.Length() - 13);
_EmitDebug(B_URL_PROTOCOL_DEBUG_TEXT, "Status line received: Code %d (%s)", _EmitDebug(B_URL_PROTOCOL_DEBUG_TEXT, "Status line received: Code %d (%s)",
atoi(statusCodeStr.String()), _ResultStatusText().String()); atoi(statusCodeStr.String()), _ResultStatusText().String());
} }
@@ -648,14 +642,14 @@ BUrlProtocolHttp::_ParseHeaders()
BString currentHeader; BString currentHeader;
if (_GetLine(currentHeader) == B_ERROR) if (_GetLine(currentHeader) == B_ERROR)
return; return;
// Empty line // Empty line
if (currentHeader.Length() == 0) { if (currentHeader.Length() == 0) {
fHeadersReceived = true; fHeadersReceived = true;
return; return;
} }
_EmitDebug(B_URL_PROTOCOL_DEBUG_HEADER_IN, "%s", currentHeader.String()); _EmitDebug(B_URL_PROTOCOL_DEBUG_HEADER_IN, "%s", currentHeader.String());
fHeaders.AddHeader(currentHeader.String()); fHeaders.AddHeader(currentHeader.String());
} }
@@ -665,7 +659,7 @@ BUrlProtocolHttp::_CopyChunkInBuffer(char** buffer, ssize_t* bytesReceived)
{ {
static ssize_t chunkSize = -1; static ssize_t chunkSize = -1;
BString chunkHeader; BString chunkHeader;
if (chunkSize >= 0) { if (chunkSize >= 0) {
if ((ssize_t)fInputBuffer.Size() >= chunkSize + 2) { if ((ssize_t)fInputBuffer.Size() >= chunkSize + 2) {
// 2 more bytes to handle the closing CR+LF // 2 more bytes to handle the closing CR+LF
@@ -684,22 +678,22 @@ BUrlProtocolHttp::_CopyChunkInBuffer(char** buffer, ssize_t* bytesReceived)
*bytesReceived = -1; *bytesReceived = -1;
return; return;
} }
// Format of a chunk header: // Format of a chunk header:
// <chunk size in hex>[; optional data] // <chunk size in hex>[; optional data]
int32 semiColonIndex = chunkHeader.FindFirst(";", 0); int32 semiColonIndex = chunkHeader.FindFirst(";", 0);
// Cut-off optional data if present // Cut-off optional data if present
if (semiColonIndex != -1) if (semiColonIndex != -1)
chunkHeader.Remove(semiColonIndex, chunkHeader.Remove(semiColonIndex,
chunkHeader.Length() - semiColonIndex); chunkHeader.Length() - semiColonIndex);
chunkSize = strtol(chunkHeader.String(), NULL, 16); chunkSize = strtol(chunkHeader.String(), NULL, 16);
PRINT(("BHP[%p] Chunk %s=%ld\n", this, chunkHeader.String(), chunkSize)); PRINT(("BHP[%p] Chunk %s=%ld\n", this, chunkHeader.String(), chunkSize));
if (chunkSize == 0) { if (chunkSize == 0) {
fContentReceived = true; fContentReceived = true;
} }
*bytesReceived = -1; *bytesReceived = -1;
*buffer = NULL; *buffer = NULL;
} }
@@ -710,46 +704,46 @@ void
BUrlProtocolHttp::_CreateRequest() BUrlProtocolHttp::_CreateRequest()
{ {
BString request; BString request;
switch (fRequestMethod) { switch (fRequestMethod) {
case B_HTTP_POST: case B_HTTP_POST:
request << "POST"; request << "POST";
break; break;
case B_HTTP_PUT: case B_HTTP_PUT:
request << "PUT"; request << "PUT";
break; break;
default: default:
case B_HTTP_GET: case B_HTTP_GET:
request << "GET"; request << "GET";
break; break;
} }
if (Url().HasPath()) if (Url().HasPath())
request << ' ' << Url().Path(); request << ' ' << Url().Path();
else else
request << " /"; request << " /";
if (Url().HasRequest()) if (Url().HasRequest())
request << '?' << Url().Request(); request << '?' << Url().Request();
if (Url().HasFragment()) if (Url().HasFragment())
request << '#' << Url().Fragment(); request << '#' << Url().Fragment();
request << ' '; request << ' ';
switch (fHttpVersion) { switch (fHttpVersion) {
case B_HTTP_11: case B_HTTP_11:
request << "HTTP/1.1"; request << "HTTP/1.1";
break; break;
default: default:
case B_HTTP_10: case B_HTTP_10:
request << "HTTP/1.0"; request << "HTTP/1.0";
break; break;
} }
_AddOutputBufferLine(request.String()); _AddOutputBufferLine(request.String());
} }
@@ -760,93 +754,77 @@ BUrlProtocolHttp::_AddHeaders()
// HTTP 1.1 additional headers // HTTP 1.1 additional headers
if (fHttpVersion == B_HTTP_11) { if (fHttpVersion == B_HTTP_11) {
fOutputHeaders.AddHeader("Host", Url().Host()); fOutputHeaders.AddHeader("Host", Url().Host());
fOutputHeaders.AddHeader("Accept", "*/*"); fOutputHeaders.AddHeader("Accept", "*/*");
fOutputHeaders.AddHeader("Accept-Encoding", "chunked"); fOutputHeaders.AddHeader("Accept-Encoding", "chunked");
// Allow the remote server to send dynamic content by chunks // Allow the remote server to send dynamic content by chunks
// rather than waiting for the full content to be generated and // rather than waiting for the full content to be generated and
// sending us data. // sending us data.
fOutputHeaders.AddHeader("Connection", "close"); fOutputHeaders.AddHeader("Connection", "close");
// Let the remote server close the connection after response since // Let the remote server close the connection after response since
// we don't handle multiple request on a single connection // we don't handle multiple request on a single connection
} }
// Classic HTTP headers // Classic HTTP headers
if (fOptUserAgent.CountChars() > 0) if (fOptUserAgent.CountChars() > 0)
fOutputHeaders.AddHeader("User-Agent", fOptUserAgent.String()); fOutputHeaders.AddHeader("User-Agent", fOptUserAgent.String());
if (fOptReferer.CountChars() > 0) if (fOptReferer.CountChars() > 0)
fOutputHeaders.AddHeader("Referer", fOptReferer.String()); fOutputHeaders.AddHeader("Referer", fOptReferer.String());
// Authentication // Authentication
if (fAuthentication.Method() != B_HTTP_AUTHENTICATION_NONE) { if (fAuthentication.Method() != B_HTTP_AUTHENTICATION_NONE) {
BString request; BString request;
switch (fRequestMethod) { switch (fRequestMethod) {
case B_HTTP_POST: case B_HTTP_POST:
request = "POST"; request = "POST";
break; break;
case B_HTTP_PUT: case B_HTTP_PUT:
request = "PUT"; request = "PUT";
break; break;
default: default:
case B_HTTP_GET: case B_HTTP_GET:
request = "GET"; request = "GET";
break; break;
} }
fOutputHeaders.AddHeader("Authorization", fOutputHeaders.AddHeader("Authorization",
fAuthentication.Authorization(fUrl, request)); fAuthentication.Authorization(fUrl, request));
} }
// Required headers for POST data // Required headers for POST data
if (fOptPostFields != NULL && fRequestMethod == B_HTTP_POST) { if (fOptPostFields != NULL && fRequestMethod == B_HTTP_POST) {
BString contentType; BString contentType;
switch (fOptPostFields->GetFormType()) { switch (fOptPostFields->GetFormType()) {
case B_HTTP_FORM_MULTIPART: case B_HTTP_FORM_MULTIPART:
contentType << "multipart/form-data; boundary=" contentType << "multipart/form-data; boundary="
<< fOptPostFields->GetMultipartBoundary() << ""; << fOptPostFields->GetMultipartBoundary() << "";
break; break;
case B_HTTP_FORM_URL_ENCODED: case B_HTTP_FORM_URL_ENCODED:
contentType << "application/x-www-form-urlencoded"; contentType << "application/x-www-form-urlencoded";
break; break;
} }
fOutputHeaders.AddHeader("Content-Type", contentType); fOutputHeaders.AddHeader("Content-Type", contentType);
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"); fOutputHeaders.AddHeader("Transfer-Encoding", "chunked");
// Request headers
for (int32 headerIndex = 0;
headerIndex < fRequestHeaders.CountHeaders();
headerIndex++) {
BHttpHeader& optHeader = fRequestHeaders[headerIndex];
int32 replaceIndex = fOutputHeaders.HasHeader(optHeader.Name());
// Add or replace the current option header to the
// output header list
if (replaceIndex == -1)
fOutputHeaders.AddHeader(optHeader.Name(), optHeader.Value());
else
fOutputHeaders[replaceIndex].SetValue(optHeader.Value());
}
// Optional headers specified by the user // Optional headers specified by the user
if (fOptHeaders != NULL) { if (fOptHeaders != NULL) {
for (int32 headerIndex = 0; for (int32 headerIndex = 0; headerIndex < fOptHeaders->CountHeaders();
headerIndex < fOptHeaders->CountHeaders(); headerIndex++) {
headerIndex++) {
BHttpHeader& optHeader = (*fOptHeaders)[headerIndex]; BHttpHeader& optHeader = (*fOptHeaders)[headerIndex];
int32 replaceIndex = fOutputHeaders.HasHeader(optHeader.Name()); int32 replaceIndex = fOutputHeaders.HasHeader(optHeader.Name());
// Add or replace the current option header to the // Add or replace the current option header to the
// output header list // output header list
if (replaceIndex == -1) if (replaceIndex == -1)
fOutputHeaders.AddHeader(optHeader.Name(), optHeader.Value()); fOutputHeaders.AddHeader(optHeader.Name(), optHeader.Value());
@@ -854,22 +832,20 @@ BUrlProtocolHttp::_AddHeaders()
fOutputHeaders[replaceIndex].SetValue(optHeader.Value()); fOutputHeaders[replaceIndex].SetValue(optHeader.Value());
} }
} }
// Context cookies // Context cookies
if (fOptSetCookies && (fContext != NULL)) { if (fOptSetCookies && (fContext != NULL)) {
BNetworkCookie* cookie; BNetworkCookie* cookie;
for (BNetworkCookieJar::UrlIterator for (BNetworkCookieJar::UrlIterator it
it(fContext->GetCookieJar().GetUrlIterator(fUrl)); = fContext->GetCookieJar().GetUrlIterator(fUrl);
(cookie = it.Next()) != NULL; (cookie = it.Next()) != NULL;)
) fOutputHeaders.AddHeader("Cookie", cookie->RawCookie(false));
fOutputHeaders.AddHeader("Cookie", cookie->RawCookie(false));
} }
// Write output headers to output stream // Write output headers to output stream
for (int32 headerIndex = 0; for (int32 headerIndex = 0; headerIndex < fOutputHeaders.CountHeaders();
headerIndex < fOutputHeaders.CountHeaders(); headerIndex++)
headerIndex++)
_AddOutputBufferLine(fOutputHeaders.HeaderAt(headerIndex).Header()); _AddOutputBufferLine(fOutputHeaders.HeaderAt(headerIndex).Header());
} }
+56 -67
View File
@@ -13,27 +13,15 @@
#include <Debug.h> #include <Debug.h>
BUrlRequest::BUrlRequest(const BUrl& url, BUrlProtocolListener* listener) BUrlRequest::BUrlRequest(const BUrl& url, BUrlProtocolListener* listener,
: BUrlContext* context)
:
fListener(listener), fListener(listener),
fUrlProtocol(NULL), fUrlProtocol(NULL),
fResult(url), fResult(url),
fContext(), fContext(context),
fUrl(), fUrl(),
fReady(false) fInitStatus(B_ERROR)
{
SetUrl(url);
}
BUrlRequest::BUrlRequest(const BUrl& url)
:
fListener(NULL),
fUrlProtocol(NULL),
fResult(url),
fContext(),
fUrl(),
fReady(false)
{ {
SetUrl(url); SetUrl(url);
} }
@@ -46,12 +34,18 @@ BUrlRequest::BUrlRequest(const BUrlRequest& other)
fResult(other.fUrl), fResult(other.fUrl),
fContext(), fContext(),
fUrl(), fUrl(),
fReady(false) fInitStatus(B_ERROR)
{ {
*this = other; *this = other;
} }
BUrlRequest::~BUrlRequest()
{
if (fUrlProtocol != NULL)
delete fUrlProtocol;
}
// #pragma mark Request parameters modification // #pragma mark Request parameters modification
@@ -60,16 +54,14 @@ BUrlRequest::SetUrl(const BUrl& url)
{ {
fUrl = url; fUrl = url;
fResult.SetUrl(url); fResult.SetUrl(url);
if (fUrlProtocol != NULL && url.Protocol() == fUrl.Protocol()) if (fUrlProtocol != NULL && url.Protocol() == fUrl.Protocol()) {
fUrlProtocol->SetUrl(url); fUrlProtocol->SetUrl(url);
else { return B_OK;
status_t err = Identify();
if (err != B_OK)
return err;
} }
return B_OK; fInitStatus = _SetupProtocol();
return fInitStatus;
} }
@@ -84,7 +76,7 @@ void
BUrlRequest::SetProtocolListener(BUrlProtocolListener* listener) BUrlRequest::SetProtocolListener(BUrlProtocolListener* listener)
{ {
fListener = listener; fListener = listener;
if (fUrlProtocol != NULL) if (fUrlProtocol != NULL)
fUrlProtocol->SetListener(listener); fUrlProtocol->SetListener(listener);
} }
@@ -95,7 +87,7 @@ BUrlRequest::SetProtocolOption(int32 option, void* value)
{ {
if (fUrlProtocol == NULL) if (fUrlProtocol == NULL)
return false; return false;
fUrlProtocol->SetOption(option, value); fUrlProtocol->SetOption(option, value);
return true; return true;
} }
@@ -129,44 +121,18 @@ BUrlRequest::Url()
status_t status_t
BUrlRequest::Identify() BUrlRequest::Start()
{
// TODO: instanciate the correct BUrlProtocol w/ the services roster
delete fUrlProtocol;
fUrlProtocol = NULL;
if (fUrl.Protocol() == "http") {
fUrlProtocol = new(std::nothrow) BUrlProtocolHttp(fUrl, false, "HTTP",
fListener, fContext,
&fResult);
fReady = true;
return B_OK;
} else if (fUrl.Protocol() == "https") {
fUrlProtocol = new(std::nothrow) BUrlProtocolHttp(fUrl, true, "HTTPS",
fListener, fContext,
&fResult);
fReady = true;
return B_OK;
}
fReady = false;
return B_NO_HANDLER_FOR_PROTOCOL;
}
status_t
BUrlRequest::Perform()
{ {
if (fUrlProtocol == NULL) { if (fUrlProtocol == NULL) {
PRINT(("BUrlRequest::Perform() : Oops, no BUrlProtocol defined!\n")); PRINT(("BUrlRequest::Perform() : Oops, no BUrlProtocol defined!\n"));
return B_ERROR; return B_ERROR;
} }
thread_id protocolThread = fUrlProtocol->Run(); thread_id protocolThread = fUrlProtocol->Run();
if (protocolThread < B_OK) if (protocolThread < B_OK)
return protocolThread; return protocolThread;
return B_OK; return B_OK;
} }
@@ -176,7 +142,7 @@ BUrlRequest::Pause()
{ {
if (fUrlProtocol == NULL) if (fUrlProtocol == NULL)
return B_ERROR; return B_ERROR;
return fUrlProtocol->Pause(); return fUrlProtocol->Pause();
} }
@@ -186,7 +152,7 @@ BUrlRequest::Resume()
{ {
if (fUrlProtocol == NULL) if (fUrlProtocol == NULL)
return B_ERROR; return B_ERROR;
return fUrlProtocol->Resume(); return fUrlProtocol->Resume();
} }
@@ -196,11 +162,11 @@ BUrlRequest::Abort()
{ {
if (fUrlProtocol == NULL) if (fUrlProtocol == NULL)
return B_ERROR; return B_ERROR;
status_t returnCode = fUrlProtocol->Stop(); status_t returnCode = fUrlProtocol->Stop();
delete fUrlProtocol; delete fUrlProtocol;
fUrlProtocol = NULL; fUrlProtocol = NULL;
return returnCode; return returnCode;
} }
@@ -208,10 +174,10 @@ BUrlRequest::Abort()
// #pragma mark Request informations // #pragma mark Request informations
bool status_t
BUrlRequest::InitCheck() const BUrlRequest::InitCheck() const
{ {
return fReady; return fInitStatus;
} }
@@ -220,7 +186,7 @@ BUrlRequest::IsRunning() const
{ {
if (fUrlProtocol == NULL) if (fUrlProtocol == NULL)
return false; return false;
return fUrlProtocol->IsRunning(); return fUrlProtocol->IsRunning();
} }
@@ -230,7 +196,7 @@ BUrlRequest::Status() const
{ {
if (fUrlProtocol == NULL) if (fUrlProtocol == NULL)
return B_ERROR; return B_ERROR;
return fUrlProtocol->Status(); return fUrlProtocol->Status();
} }
@@ -248,6 +214,29 @@ BUrlRequest::operator=(const BUrlRequest& other)
fContext = other.fContext; fContext = other.fContext;
fResult = BUrlResult(other.fUrl); fResult = BUrlResult(other.fUrl);
SetUrl(other.fUrl); SetUrl(other.fUrl);
return *this; return *this;
} }
status_t
BUrlRequest::_SetupProtocol()
{
// TODO: instanciate the correct BUrlProtocol w/ the services roster
delete fUrlProtocol;
fUrlProtocol = NULL;
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;
}
@@ -14,7 +14,7 @@
BUrlSynchronousRequest::BUrlSynchronousRequest(BUrl& url) BUrlSynchronousRequest::BUrlSynchronousRequest(BUrl& url)
: :
BUrlRequest(url, this), BUrlRequest(url, this),
fRequestComplete(false) fRequestComplete(false)
{ {
@@ -26,8 +26,8 @@ BUrlSynchronousRequest::Perform()
{ {
SetProtocolListener(this); SetProtocolListener(this);
fRequestComplete = false; fRequestComplete = false;
return BUrlRequest::Perform(); return Start();
} }
@@ -36,7 +36,7 @@ BUrlSynchronousRequest::WaitUntilCompletion()
{ {
while (!fRequestComplete) while (!fRequestComplete)
snooze(10000); snooze(10000);
return B_OK; return B_OK;
} }
@@ -70,7 +70,7 @@ BUrlSynchronousRequest::HeadersReceived(BUrlProtocol*)
void void
BUrlSynchronousRequest::DataReceived(BUrlProtocol*, const char*, BUrlSynchronousRequest::DataReceived(BUrlProtocol*, const char*,
ssize_t size) ssize_t size)
{ {
PRINT(("SynchronousRequest::DataReceived(%zd)\n", size)); PRINT(("SynchronousRequest::DataReceived(%zd)\n", size));
@@ -78,7 +78,7 @@ BUrlSynchronousRequest::DataReceived(BUrlProtocol*, const char*,
void void
BUrlSynchronousRequest::DownloadProgress(BUrlProtocol*, BUrlSynchronousRequest::DownloadProgress(BUrlProtocol*,
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,
@@ -98,7 +98,7 @@ BUrlSynchronousRequest::UploadProgress(BUrlProtocol*, ssize_t bytesSent,
void void
BUrlSynchronousRequest::RequestCompleted(BUrlProtocol* caller, bool success) BUrlSynchronousRequest::RequestCompleted(BUrlProtocol* 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())));
fRequestComplete = true; fRequestComplete = true;
} }