hrev45267 adds 1 changeset to branch 'master' old head: 344de4ccd12eb0fe63d7d3c8aece5138fe1909bd new head: 2675e31a0c1e2394bca58cf2f2511525c49cd7ef overview: http://cgit.haiku-os.org/haiku/log/?qt=range&q=2675e31+%5E344de4c ---------------------------------------------------------------------------- 2675e31: BUrlRequest: fix various issues * Remove unused headers interface from BUrlProtocol * Change confusing function names * Style fixes and whitespace cleanup [ Hamish Morrison <hamishm53@xxxxxxxxx> ] ---------------------------------------------------------------------------- Revision: hrev45267 Commit: 2675e31a0c1e2394bca58cf2f2511525c49cd7ef URL: http://cgit.haiku-os.org/haiku/commit/?id=2675e31 Author: Hamish Morrison <hamishm53@xxxxxxxxx> Date: Sun Feb 10 20:36:34 2013 UTC ---------------------------------------------------------------------------- 7 files changed, 324 insertions(+), 362 deletions(-) headers/os/net/UrlProtocol.h | 34 +- headers/os/net/UrlProtocolHttp.h | 58 +-- headers/os/net/UrlRequest.h | 25 +- src/kits/network/libnetapi/UrlProtocol.cpp | 54 +-- src/kits/network/libnetapi/UrlProtocolHttp.cpp | 378 +++++++++---------- src/kits/network/libnetapi/UrlRequest.cpp | 123 +++--- .../network/libnetapi/UrlSynchronousRequest.cpp | 14 +- ---------------------------------------------------------------------------- diff --git a/headers/os/net/UrlProtocol.h b/headers/os/net/UrlProtocol.h index 2d95d8f..f177dbb 100644 --- a/headers/os/net/UrlProtocol.h +++ b/headers/os/net/UrlProtocol.h @@ -15,14 +15,14 @@ class BUrlProtocol { public: - BUrlProtocol(const BUrl& url, + 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 @@ -39,7 +39,7 @@ public: // 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(); @@ -51,27 +51,25 @@ public: 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; - // TODO: Does not belong here. - BHttpHeaders& Headers() { return fRequestHeaders; } - + // URL protocol informations bool IsRunning() const; status_t Status() const; - virtual const char* StatusString(status_t threadStatus) + virtual const char* StatusString(status_t threadStatus) const; - - + + protected: static int32 _ThreadEntry(void* arg); virtual status_t _ProtocolLoop(); - virtual void _EmitDebug(BUrlProtocolDebugMessage type, + virtual void _EmitDebug(BUrlProtocolDebugMessage type, const char* format, ...); // URL result parameters access @@ -79,15 +77,13 @@ protected: BHttpHeaders& _ResultHeaders(); void _SetResultStatusCode(int32 statusCode); BString& _ResultStatusText(); - + protected: BUrl fUrl; - BHttpHeaders fRequestHeaders; - // TODO: Does not belong here. BUrlResult* fResult; BUrlContext* fContext; BUrlProtocolListener* fListener; - + bool fQuit; bool fRunning; status_t fThreadStatus; @@ -110,7 +106,7 @@ enum { B_PROT_WRITE_FAILED, B_PROT_READ_FAILED, B_PROT_NO_MEMORY, - B_PROT_PROTOCOL_ERROR, + B_PROT_PROTOCOL_ERROR, // Thread status over this one are guaranteed to be // errors B_PROT_THREAD_STATUS__END @@ -118,18 +114,18 @@ enum { 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; }; diff --git a/headers/os/net/UrlProtocolHttp.h b/headers/os/net/UrlProtocolHttp.h index 1902827..e924aed 100644 --- a/headers/os/net/UrlProtocolHttp.h +++ b/headers/os/net/UrlProtocolHttp.h @@ -30,7 +30,7 @@ public: virtual ~BUrlProtocolHttp(); virtual status_t SetOption(uint32 option, void* value); - + static bool IsInformationalStatusCode(int16 code); static bool IsSuccessStatusCode(int16 code); static bool IsRedirectionStatusCode(int16 code); @@ -39,49 +39,49 @@ public: static int16 StatusCodeClass(int16 code); virtual const char* StatusString(status_t threadStatus) const; - + private: void _ResetOptions(); status_t _ProtocolLoop(); bool _ResolveHostName(); status_t _MakeRequest(); - + void _CreateRequest(); void _AddHeaders(); - + status_t _GetLine(BString& destString); - + void _ParseStatus(); void _ParseHeaders(); - - void _CopyChunkInBuffer(char** buffer, + + void _CopyChunkInBuffer(char** buffer, ssize_t* bytesReceived); - + void _AddOutputBufferLine(const char* line); - - + + private: BAbstractSocket* fSocket; BNetworkAddress fRemoteAddr; bool fSSL; - + int8 fRequestMethod; int8 fHttpVersion; - + BString fOutputBuffer; BNetBuffer fInputBuffer; - + BHttpHeaders fHeaders; BHttpAuthentication fAuthentication; - + // Request status BHttpHeaders fOutputHeaders; bool fStatusReceived; bool fHeadersReceived; bool fContentReceived; bool fTrailingHeadersReceived; - - + + // Protocol options uint8 fOptMaxRedirs; BString fOptReferer; @@ -128,21 +128,21 @@ enum { enum { B_HTTPOPT_METHOD = 0, // (int) Request method (see B_HTTP_GET, ...) - B_HTTPOPT_FOLLOWLOCATION, + B_HTTPOPT_FOLLOWLOCATION, // (bool) Follow Location: headers - B_HTTPOPT_MAXREDIRS, + B_HTTPOPT_MAXREDIRS, // (int) Max relocation - B_HTTPOPT_HEADERS, + B_HTTPOPT_HEADERS, // (BHttpHeaders*) Headers to be sent - B_HTTPOPT_REFERER, + B_HTTPOPT_REFERER, // (string) Referer - B_HTTPOPT_USERAGENT, + B_HTTPOPT_USERAGENT, // (string) User-Agent - B_HTTPOPT_SETCOOKIES, + B_HTTPOPT_SETCOOKIES, // (bool) Send cookies from context - B_HTTPOPT_DISCARD_DATA, + B_HTTPOPT_DISCARD_DATA, // (bool) Discard incoming data (still notified) - B_HTTPOPT_DISABLE_LISTENER, + B_HTTPOPT_DISABLE_LISTENER, // (bool) Don't send notification to the listener B_HTTPOPT_AUTOREFERER, // (bool) Automatically set the Referer header @@ -156,7 +156,7 @@ enum { // (string) Authentication password B_HTTPOPT_AUTHMETHOD, // (int) Allowed authentication methods (see BHttpAuthenticationMethod) - + B_HTTPOPT__OPT_NUM }; @@ -179,7 +179,7 @@ enum http_status_code { B_HTTP_STATUS_CONTINUE = B_HTTP_STATUS__INFORMATIONAL_BASE, B_HTTP_STATUS_SWITCHING_PROTOCOLS, B_HTTP_STATUS__INFORMATIONAL_END, - + // Success status codes B_HTTP_STATUS__SUCCESS_BASE = 200, 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_PARTIAL_CONTENT, B_HTTP_STATUS__SUCCESS_END, - + // Redirection status codes B_HTTP_STATUS__REDIRECTION_BASE = 300, 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_TEMPORARY_REDIRECT, B_HTTP_STATUS__REDIRECTION_END, - + // Client error status codes B_HTTP_STATUS__CLIENT_ERROR_BASE = 400, 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_EXPECTATION_FAILED, B_HTTP_STATUS__CLIENT_ERROR_END, - + // Server error status codes B_HTTP_STATUS__SERVER_ERROR_BASE = 500, B_HTTP_STATUS_INTERNAL_SERVER_ERROR = B_HTTP_STATUS__SERVER_ERROR_BASE, diff --git a/headers/os/net/UrlRequest.h b/headers/os/net/UrlRequest.h index 984dfa4..d036783 100644 --- a/headers/os/net/UrlRequest.h +++ b/headers/os/net/UrlRequest.h @@ -22,36 +22,34 @@ enum { class BUrlRequest { public: BUrlRequest(const BUrl& url, - BUrlProtocolListener* listener); - BUrlRequest(const BUrl& url); + BUrlProtocolListener* listener = NULL, + BUrlContext* context = NULL); BUrlRequest(const BUrlRequest& other); - virtual ~BUrlRequest() { }; + virtual ~BUrlRequest(); // Request parameters modification status_t SetUrl(const BUrl& url); void SetContext(BUrlContext* context); void SetProtocolListener( BUrlProtocolListener* listener); - bool SetProtocolOption(int32 option, + bool SetProtocolOption(int32 option, void* value); // Request parameters access const BUrlProtocol* Protocol(); const BUrlResult& Result(); const BUrl& Url(); - + // Request control - status_t Identify(); - virtual status_t Perform(); - // TODO: Rename to Run() perhaps? "Perform" is used for FBC stuff. + virtual status_t Start(); virtual status_t Pause(); virtual status_t Resume(); virtual status_t Abort(); - + // Request informations - virtual bool InitCheck() const; + virtual status_t InitCheck() const; bool IsRunning() const; status_t Status() const; - + // Overloaded members BUrlRequest& operator=(const BUrlRequest& other); @@ -62,7 +60,10 @@ protected: BUrlResult fResult; BUrlContext* fContext; BUrl fUrl; - bool fReady; + status_t fInitStatus; + +private: + status_t _SetupProtocol(); }; #endif // _B_URL_REQUEST_H_ diff --git a/src/kits/network/libnetapi/UrlProtocol.cpp b/src/kits/network/libnetapi/UrlProtocol.cpp index 358f641..d25c19a 100644 --- a/src/kits/network/libnetapi/UrlProtocol.cpp +++ b/src/kits/network/libnetapi/UrlProtocol.cpp @@ -28,9 +28,9 @@ static const char* kProtocolThreadStrStatus[B_PROT_THREAD_STATUS__END+1] BUrlProtocol::BUrlProtocol(const BUrl& url, BUrlProtocolListener* listener, - BUrlContext* context, BUrlResult* result, const char* threadName, + BUrlContext* context, BUrlResult* result, const char* threadName, const char* protocolName) - : + : fUrl(url), fResult(result), fContext(context), @@ -61,20 +61,20 @@ BUrlProtocol::Run() "[urlProtocol=%p]!\n", this)); return fThreadId; } - - fThreadId = spawn_thread(BUrlProtocol::_ThreadEntry, fThreadName, + + 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", + PRINT(("BUrlProtocol::Run() : Failed to resume thread %ld\n", fThreadId)); return launchErr; } - + fRunning = true; return fThreadId; } @@ -101,11 +101,11 @@ BUrlProtocol::Stop() { if (!fRunning) return B_ERROR; - + status_t threadStatus = B_OK; fQuit = true; - - wait_for_thread(fThreadId, &threadStatus); + + wait_for_thread(fThreadId, &threadStatus); return threadStatus; } @@ -119,7 +119,7 @@ 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; } @@ -130,7 +130,7 @@ BUrlProtocol::SetResult(BUrlResult* result) { if (IsRunning()) return B_ERROR; - + fResult = result; return B_OK; } @@ -138,10 +138,10 @@ BUrlProtocol::SetResult(BUrlResult* result) status_t BUrlProtocol::SetContext(BUrlContext* context) -{ +{ if (IsRunning()) return B_ERROR; - + fContext = context; return B_OK; } @@ -152,7 +152,7 @@ BUrlProtocol::SetListener(BUrlProtocolListener* listener) { if (IsRunning()) return B_ERROR; - + fListener = listener; return B_OK; } @@ -226,23 +226,23 @@ BUrlProtocol::StatusString(status_t threadStatus) const // #pragma mark Thread management - + /*static*/ int32 BUrlProtocol::_ThreadEntry(void* arg) { - BUrlProtocol* urlProtocol = reinterpret_cast<BUrlProtocol*>(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, + urlProtocol->fListener->RequestCompleted(urlProtocol, protocolLoopExitStatus == B_PROT_SUCCESS); - + return B_OK; } @@ -253,13 +253,13 @@ BUrlProtocol::_ProtocolLoop() // Dummy _ProtocolLoop while (!fQuit) snooze(1000); - + return B_PROT_SUCCESS; } void -BUrlProtocol::_EmitDebug(BUrlProtocolDebugMessage type, +BUrlProtocol::_EmitDebug(BUrlProtocolDebugMessage type, const char* format, ...) { if (fListener == NULL) @@ -267,7 +267,7 @@ BUrlProtocol::_EmitDebug(BUrlProtocolDebugMessage type, va_list arguments; va_start(arguments, format); - + char debugMsg[256]; vsnprintf(debugMsg, 256, format, arguments); fListener->DebugMessage(this, type, debugMsg); @@ -275,7 +275,7 @@ BUrlProtocol::_EmitDebug(BUrlProtocolDebugMessage type, } -BMallocIO& +BMallocIO& BUrlProtocol::_ResultRawData() { return fResult->fRawData; diff --git a/src/kits/network/libnetapi/UrlProtocolHttp.cpp b/src/kits/network/libnetapi/UrlProtocolHttp.cpp index 4093649..4b7d864 100644 --- a/src/kits/network/libnetapi/UrlProtocolHttp.cpp +++ b/src/kits/network/libnetapi/UrlProtocolHttp.cpp @@ -31,10 +31,10 @@ static const char* kHttpProtocolThreadStrStatus[ }; -BUrlProtocolHttp::BUrlProtocolHttp(BUrl& url, bool ssl, - const char *protocolName, BUrlProtocolListener* listener, - BUrlContext* context, BUrlResult* result) - : +BUrlProtocolHttp::BUrlProtocolHttp(BUrl& url, bool ssl, + const char* protocolName, BUrlProtocolListener* listener, + BUrlContext* context, BUrlResult* result) + : BUrlProtocol(url, listener, context, result, "BUrlProtocol.HTTP", protocolName), fSSL(ssl), fRequestMethod(B_HTTP_GET), @@ -45,7 +45,6 @@ BUrlProtocolHttp::BUrlProtocolHttp(BUrl& url, bool ssl, fSocket = new BSecureSocket(); else fSocket = new BSocket(); - } @@ -59,67 +58,67 @@ status_t BUrlProtocolHttp::SetOption(uint32 name, void* value) { BUrlProtocolOption option(value); - + switch (name) { case B_HTTPOPT_METHOD: fRequestMethod = option.Int8(); break; - + case B_HTTPOPT_FOLLOWLOCATION: fOptFollowLocation = option.Bool(); break; - + case B_HTTPOPT_MAXREDIRS: fOptMaxRedirs = option.Int8(); break; - + case B_HTTPOPT_REFERER: fOptReferer = option.String(); break; - + case B_HTTPOPT_USERAGENT: fOptUserAgent = option.String(); break; - + case B_HTTPOPT_HEADERS: fOptHeaders = reinterpret_cast<BHttpHeaders*>(option.Pointer()); break; - + case B_HTTPOPT_DISCARD_DATA: fOptDiscardData = option.Bool(); break; - + case B_HTTPOPT_DISABLE_LISTENER: fOptDisableListener = option.Bool(); break; - + case B_HTTPOPT_AUTOREFERER: fOptAutoReferer = option.Bool(); break; - + case B_HTTPOPT_POSTFIELDS: fOptPostFields = reinterpret_cast<BHttpForm*>(option.Pointer()); - + if (fOptPostFields != NULL) fRequestMethod = B_HTTP_POST; break; - + case B_HTTPOPT_INPUTDATA: fOptInputData = reinterpret_cast<BDataIO*>(option.Pointer()); break; - + case B_HTTPOPT_AUTHUSERNAME: fOptUsername = option.String(); break; - + case B_HTTPOPT_AUTHPASSWORD: fOptPassword = option.String(); break; - + default: return B_ERROR; } - + return B_OK; } @@ -177,7 +176,7 @@ BUrlProtocolHttp::StatusCodeClass(int16 code) return B_HTTP_STATUS_CLASS_CLIENT_ERROR; else if (BUrlProtocolHttp::IsServerErrorStatusCode(code)) return B_HTTP_STATUS_CLASS_SERVER_ERROR; - + 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) return BUrlProtocol::StatusString(-1); else - return kHttpProtocolThreadStrStatus[threadStatus + return kHttpProtocolThreadStrStatus[threadStatus - B_PROT_THREAD_STATUS__END]; } - + void BUrlProtocolHttp::_ResetOptions() { @@ -204,7 +203,7 @@ BUrlProtocolHttp::_ResetOptions() fOptUserAgent = "Services Kit (Haiku)"; fOptUsername = ""; fOptPassword = ""; - fOptAuthMethods = B_HTTP_AUTHENTICATION_BASIC | B_HTTP_AUTHENTICATION_DIGEST + fOptAuthMethods = B_HTTP_AUTHENTICATION_BASIC | B_HTTP_AUTHENTICATION_DIGEST | B_HTTP_AUTHENTICATION_IE_DIGEST; fOptHeaders = NULL; fOptPostFields = NULL; @@ -217,16 +216,16 @@ BUrlProtocolHttp::_ResetOptions() #include <stdio.h> status_t BUrlProtocolHttp::_ProtocolLoop() -{ +{ printf("UHP[%p]::{Loop} %s\n", this, fUrl.UrlString().String()); // Initialize the request redirection loop int8 maxRedirs = fOptMaxRedirs; bool newRequest; - + do { newRequest = false; - + // Result reset fOutputBuffer.Truncate(0, true); fOutputHeaders.Clear(); @@ -234,61 +233,61 @@ BUrlProtocolHttp::_ProtocolLoop() _ResultHeaders().Clear(); _ResultRawData().Seek(SEEK_SET, 0); _ResultRawData().SetSize(0); - + if (!_ResolveHostName()) { _EmitDebug(B_URL_PROTOCOL_DEBUG_ERROR, "Unable to resolve hostname, aborting."); return B_PROT_CANT_RESOLVE_HOSTNAME; } - + _CreateRequest(); _AddHeaders(); _AddOutputBufferLine(""); - + status_t requestStatus = _MakeRequest(); if (requestStatus != B_PROT_SUCCESS) return requestStatus; - + // Prepare the referer for the next request if needed if (fOptAutoReferer) fOptReferer = fUrl.UrlString(); - + switch (StatusCodeClass(fResult->StatusCode())) { case B_HTTP_STATUS_CLASS_INFORMATIONAL: // Header 100:continue should have been // handled in the _MakeRequest read loop break; - + case B_HTTP_STATUS_CLASS_SUCCESS: break; - + case B_HTTP_STATUS_CLASS_REDIRECTION: // Redirection has been explicitly disabled if (!fOptFollowLocation) break; - + // TODO: Some browsers seems to translate POST requests to // GET when following a 302 redirection if (fResult->StatusCode() == B_HTTP_STATUS_MOVED_PERMANENTLY) { BString locationUrl = fHeaders["Location"]; - + // Absolute path if (locationUrl[0] == '/') fUrl.SetPath(locationUrl); // URI else fUrl.SetUrlString(locationUrl); - + if (--maxRedirs > 0) { newRequest = true; - + _EmitDebug(B_URL_PROTOCOL_DEBUG_TEXT, - "Following: %s\n", + "Following: %s\n", fUrl.UrlString().String()); } } break; - + case B_HTTP_STATUS_CLASS_CLIENT_ERROR: switch (fResult->StatusCode()) { case B_HTTP_STATUS_UNAUTHORIZED: @@ -296,7 +295,7 @@ BUrlProtocolHttp::_ProtocolLoop() newRequest = false; break; } - + newRequest = false; if (fOptUsername.Length() > 0 && fAuthentication.Initialize(fHeaders["WWW-Authenticate"]) @@ -308,21 +307,20 @@ BUrlProtocolHttp::_ProtocolLoop() break; } break; - + case B_HTTP_STATUS_CLASS_SERVER_ERROR: break; - + default: case B_HTTP_STATUS_CLASS_INVALID: break; } } while (newRequest); - + _EmitDebug(B_URL_PROTOCOL_DEBUG_TEXT, - "%ld headers and %ld bytes of data remaining", - fHeaders.CountHeaders(), - fInputBuffer.Size()); - + "%ld headers and %ld bytes of data remaining", + fHeaders.CountHeaders(), fInputBuffer.Size()); + if (fResult->StatusCode() == 404) return B_PROT_HTTP_NOT_FOUND; @@ -335,27 +333,23 @@ BUrlProtocolHttp::_ResolveHostName() { _EmitDebug(B_URL_PROTOCOL_DEBUG_TEXT, "Resolving %s", fUrl.UrlString().String()); - + if (fUrl.HasPort()) fRemoteAddr = BNetworkAddress(fUrl.Host(), fUrl.Port()); else { - if (fSSL) - fRemoteAddr = BNetworkAddress(fUrl.Host(), 443); - else - fRemoteAddr = BNetworkAddress(fUrl.Host(), 80); + fRemoteAddr = BNetworkAddress(fUrl.Host(), fSSL ? 443 : 80); } - + if (fRemoteAddr.InitCheck() != B_OK) return false; - + //! ProtocolHook:HostnameResolved if (fListener != NULL) - fListener->HostnameResolved(this, - const_cast<const char*>(fRemoteAddr.ToString().String())); - - _EmitDebug(B_URL_PROTOCOL_DEBUG_TEXT, "Hostname resolved to: %s", - fRemoteAddr.ToString().String()); - + fListener->HostnameResolved(this, fRemoteAddr.ToString().String()); + + _EmitDebug(B_URL_PROTOCOL_DEBUG_TEXT, "Hostname resolved to: %s", + fRemoteAddr.ToString().String()); + return true; } @@ -363,58 +357,58 @@ BUrlProtocolHttp::_ResolveHostName() status_t BUrlProtocolHttp::_MakeRequest() { - _EmitDebug(B_URL_PROTOCOL_DEBUG_TEXT, "Connection to %s.", + _EmitDebug(B_URL_PROTOCOL_DEBUG_TEXT, "Connection to %s.", fUrl.Authority().String()); status_t connectError = fSocket->Connect(fRemoteAddr); - + if (connectError != B_OK) { _EmitDebug(B_URL_PROTOCOL_DEBUG_ERROR, "Socket connection error."); return B_PROT_CONNECTION_FAILED; } - + //! ProtocolHook:ConnectionOpened if (fListener != NULL) fListener->ConnectionOpened(this); - + _EmitDebug(B_URL_PROTOCOL_DEBUG_TEXT, "Connection opened."); - + _EmitDebug(B_URL_PROTOCOL_DEBUG_TEXT, "Sending request (size=%d)", fOutputBuffer.Length()); fSocket->Write(fOutputBuffer.String(), fOutputBuffer.Length()); fOutputBuffer.Truncate(0); _EmitDebug(B_URL_PROTOCOL_DEBUG_TEXT, "Request sent."); - + if (fRequestMethod == B_HTTP_POST && fOptPostFields != NULL) { if (fOptPostFields->GetFormType() != B_HTTP_FORM_MULTIPART) { fOutputBuffer = fOptPostFields->RawData(); - _EmitDebug(B_URL_PROTOCOL_DEBUG_TRANSFER_OUT, + _EmitDebug(B_URL_PROTOCOL_DEBUG_TRANSFER_OUT, fOutputBuffer.String()); fSocket->Write(fOutputBuffer.String(), fOutputBuffer.Length()); } else { for (BHttpForm::Iterator it = fOptPostFields->GetIterator(); const BHttpFormData* currentField = it.Next(); ) { - _EmitDebug(B_URL_PROTOCOL_DEBUG_TRANSFER_OUT, + _EmitDebug(B_URL_PROTOCOL_DEBUG_TRANSFER_OUT, it.MultipartHeader().String()); - fSocket->Write(it.MultipartHeader().String(), + fSocket->Write(it.MultipartHeader().String(), it.MultipartHeader().Length()); - + switch (currentField->Type()) { case B_HTTPFORM_UNKNOWN: ASSERT(0); break; - + case B_HTTPFORM_STRING: - fSocket->Write(currentField->String().String(), + fSocket->Write(currentField->String().String(), currentField->String().Length()); break; - + case B_HTTPFORM_FILE: { - BFile upFile(currentField->File().Path(), + BFile upFile(currentField->File().Path(), B_READ_ONLY); char readBuffer[1024]; - ssize_t readSize; + ssize_t readSize; readSize = upFile.Read(readBuffer, 1024); while (readSize > 0) { @@ -423,45 +417,45 @@ BUrlProtocolHttp::_MakeRequest() } } break; - + case B_HTTPFORM_BUFFER: - fSocket->Write(currentField->Buffer(), + fSocket->Write(currentField->Buffer(), currentField->BufferSize()); break; } - + fSocket->Write("\r\n", 2); } - - fSocket->Write(fOptPostFields->GetMultipartFooter().String(), + + fSocket->Write(fOptPostFields->GetMultipartFooter().String(), 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) { char outputTempBuffer[1024]; ssize_t read = 0; - + while (read != -1) { read = fOptInputData->Read(outputTempBuffer, 1024); - + if (read > 0) { 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("0\r\n\r\n", 5); } fOutputBuffer.Truncate(0, true); - + fStatusReceived = false; fHeadersReceived = false; - + // Receive loop bool receiveEnd = false; bool parseEnd = false; @@ -473,38 +467,38 @@ BUrlProtocolHttp::_MakeRequest() ssize_t bytesTotal = 0; char* inputTempBuffer = NULL; fQuit = false; - + while (!fQuit && !(receiveEnd && parseEnd)) { if (!receiveEnd) { fSocket->WaitForReadable(); BNetBuffer chunk(receiveBufferSize); bytesRead = fSocket->Read(chunk.Data(), receiveBufferSize); - + if (bytesRead < 0) { readError = true; fQuit = true; - continue; + continue; } else if (bytesRead == 0) receiveEnd = true; - + fInputBuffer.AppendData(chunk.Data(), bytesRead); } else bytesRead = 0; - + if (!fStatusReceived) { _ParseStatus(); - + //! ProtocolHook:ResponseStarted if (fStatusReceived && fListener != NULL) fListener->ResponseStarted(this); } else if (!fHeadersReceived) { _ParseHeaders(); - + if (fHeadersReceived) { receiveBufferSize = kHttpProtocolReceiveBufferSize; _ResultHeaders() = fHeaders; - + //! ProtocolHook:HeadersReceived if (fListener != NULL) fListener->HeadersReceived(this); @@ -516,10 +510,10 @@ BUrlProtocolHttp::_MakeRequest() } } } - + if (BString(fHeaders["Transfer-Encoding"]) == "chunked") readByChunks = true; - + int32 index = fHeaders.HasHeader("Content-Length"); if (index != B_ERROR) bytesTotal = atoi(fHeaders.HeaderAt(index).Value()); @@ -531,7 +525,7 @@ BUrlProtocolHttp::_MakeRequest() // chunk in buffer before handling it if (readByChunks) { _CopyChunkInBuffer(&inputTempBuffer, &bytesRead); - + // A chunk of 0 bytes indicates the end of the chunked transfer if (bytesRead == 0) { receiveEnd = true; @@ -539,50 +533,50 @@ BUrlProtocolHttp::_MakeRequest() } else { bytesRead = fInputBuffer.Size(); - + if (bytesRead > 0) { inputTempBuffer = new char[bytesRead]; fInputBuffer.RemoveData(inputTempBuffer, bytesRead); } } - + if (bytesRead > 0) { bytesReceived += bytesRead; - _EmitDebug(B_URL_PROTOCOL_DEBUG_TRANSFER_IN, "%d bytes", + _EmitDebug(B_URL_PROTOCOL_DEBUG_TRANSFER_IN, "%d bytes", bytesRead); - + if (fListener != NULL) { fListener->DataReceived(this, inputTempBuffer, bytesRead); - fListener->DownloadProgress(this, bytesReceived, + fListener->DownloadProgress(this, bytesReceived, bytesTotal); } - - ssize_t dataWrite = _ResultRawData().Write(inputTempBuffer, + + ssize_t dataWrite = _ResultRawData().Write(inputTempBuffer, bytesRead); - + if (dataWrite != bytesRead) { - _EmitDebug(B_URL_PROTOCOL_DEBUG_ERROR, - "Unable to write %dbytes of data (%d).", bytesRead, + _EmitDebug(B_URL_PROTOCOL_DEBUG_ERROR, + "Unable to write %dbytes of data (%d).", bytesRead, dataWrite); return B_PROT_NO_MEMORY; } - + if (bytesTotal > 0 && bytesReceived >= bytesTotal) receiveEnd = true; - + delete[] inputTempBuffer; - } + } } - + parseEnd = (fInputBuffer.Size() == 0); } - + fSocket->Disconnect(); - + if (readError) 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 uint32 characterIndex = 0; - - while ((characterIndex < fInputBuffer.Size()) + + while ((characterIndex < fInputBuffer.Size()) && ((fInputBuffer.Data())[characterIndex] != '\n')) characterIndex++; - + if (characterIndex == fInputBuffer.Size()) return B_ERROR; - + char* temporaryBuffer = new(std::nothrow) char[characterIndex + 1]; fInputBuffer.RemoveData(temporaryBuffer, characterIndex + 1); - + // Strip end-of-line character(s) if (temporaryBuffer[characterIndex-1] == '\r') destString.SetTo(temporaryBuffer, characterIndex - 1); else - destString.SetTo(temporaryBuffer, characterIndex); - + destString.SetTo(temporaryBuffer, characterIndex); + delete[] temporaryBuffer; return B_OK; } @@ -624,19 +618,19 @@ BUrlProtocolHttp::_ParseStatus() BString statusLine; if (_GetLine(statusLine) == B_ERROR) return; - + if (statusLine.CountChars() < 12) return; - + fStatusReceived = true; - + BString statusCodeStr; BString statusText; statusLine.CopyInto(statusCodeStr, 9, 3); _SetResultStatusCode(atoi(statusCodeStr.String())); - + statusLine.CopyInto(_ResultStatusText(), 13, statusLine.Length() - 13); - + _EmitDebug(B_URL_PROTOCOL_DEBUG_TEXT, "Status line received: Code %d (%s)", atoi(statusCodeStr.String()), _ResultStatusText().String()); } @@ -648,14 +642,14 @@ BUrlProtocolHttp::_ParseHeaders() BString currentHeader; if (_GetLine(currentHeader) == B_ERROR) return; - + // Empty line if (currentHeader.Length() == 0) { fHeadersReceived = true; 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()); } @@ -665,7 +659,7 @@ BUrlProtocolHttp::_CopyChunkInBuffer(char** buffer, ssize_t* bytesReceived) { static ssize_t chunkSize = -1; BString chunkHeader; - + if (chunkSize >= 0) { if ((ssize_t)fInputBuffer.Size() >= chunkSize + 2) { // 2 more bytes to handle the closing CR+LF @@ -684,22 +678,22 @@ BUrlProtocolHttp::_CopyChunkInBuffer(char** buffer, ssize_t* bytesReceived) *bytesReceived = -1; return; } - + // Format of a chunk header: // <chunk size in hex>[; optional data] int32 semiColonIndex = chunkHeader.FindFirst(";", 0); - + // Cut-off optional data if present if (semiColonIndex != -1) - chunkHeader.Remove(semiColonIndex, + chunkHeader.Remove(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)); if (chunkSize == 0) { fContentReceived = true; } - + *bytesReceived = -1; *buffer = NULL; } @@ -710,46 +704,46 @@ void BUrlProtocolHttp::_CreateRequest() { BString request; - - switch (fRequestMethod) { + + switch (fRequestMethod) { case B_HTTP_POST: request << "POST"; break; - + case B_HTTP_PUT: request << "PUT"; break; - + default: case B_HTTP_GET: request << "GET"; break; } - + if (Url().HasPath()) request << ' ' << Url().Path(); else request << " /"; - + if (Url().HasRequest()) request << '?' << Url().Request(); - + if (Url().HasFragment()) request << '#' << Url().Fragment(); - + request << ' '; - + switch (fHttpVersion) { case B_HTTP_11: request << "HTTP/1.1"; break; - + default: case B_HTTP_10: request << "HTTP/1.0"; break; } - + _AddOutputBufferLine(request.String()); } @@ -760,93 +754,77 @@ BUrlProtocolHttp::_AddHeaders() // HTTP 1.1 additional headers if (fHttpVersion == B_HTTP_11) { fOutputHeaders.AddHeader("Host", Url().Host()); - + fOutputHeaders.AddHeader("Accept", "*/*"); 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 // sending us data. - + 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 } // Classic HTTP headers if (fOptUserAgent.CountChars() > 0) fOutputHeaders.AddHeader("User-Agent", fOptUserAgent.String()); - + if (fOptReferer.CountChars() > 0) fOutputHeaders.AddHeader("Referer", fOptReferer.String()); - + // Authentication if (fAuthentication.Method() != B_HTTP_AUTHENTICATION_NONE) { BString request; - switch (fRequestMethod) { + switch (fRequestMethod) { case B_HTTP_POST: request = "POST"; break; - + case B_HTTP_PUT: request = "PUT"; break; - + default: case B_HTTP_GET: request = "GET"; break; } - - fOutputHeaders.AddHeader("Authorization", + + fOutputHeaders.AddHeader("Authorization", fAuthentication.Authorization(fUrl, request)); } - + // Required headers for POST data if (fOptPostFields != NULL && fRequestMethod == B_HTTP_POST) { BString contentType; - + switch (fOptPostFields->GetFormType()) { case B_HTTP_FORM_MULTIPART: contentType << "multipart/form-data; boundary=" << fOptPostFields->GetMultipartBoundary() << ""; break; - + case B_HTTP_FORM_URL_ENCODED: contentType << "application/x-www-form-urlencoded"; break; } - + fOutputHeaders.AddHeader("Content-Type", contentType); - fOutputHeaders.AddHeader("Content-Length", + fOutputHeaders.AddHeader("Content-Length", fOptPostFields->ContentLength()); - } else if (fOptInputData != NULL + } else if (fOptInputData != NULL && (fRequestMethod == B_HTTP_POST || fRequestMethod == B_HTTP_PUT)) 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 - if (fOptHeaders != NULL) { - for (int32 headerIndex = 0; - headerIndex < fOptHeaders->CountHeaders(); - headerIndex++) { + if (fOptHeaders != NULL) { + for (int32 headerIndex = 0; headerIndex < fOptHeaders->CountHeaders(); + headerIndex++) { BHttpHeader& optHeader = (*fOptHeaders)[headerIndex]; 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 if (replaceIndex == -1) fOutputHeaders.AddHeader(optHeader.Name(), optHeader.Value()); @@ -854,22 +832,20 @@ BUrlProtocolHttp::_AddHeaders() fOutputHeaders[replaceIndex].SetValue(optHeader.Value()); } } - + // Context cookies if (fOptSetCookies && (fContext != NULL)) { BNetworkCookie* cookie; - - for (BNetworkCookieJar::UrlIterator - it(fContext->GetCookieJar().GetUrlIterator(fUrl)); - (cookie = it.Next()) != NULL; - ) - fOutputHeaders.AddHeader("Cookie", cookie->RawCookie(false)); + + for (BNetworkCookieJar::UrlIterator it + = fContext->GetCookieJar().GetUrlIterator(fUrl); + (cookie = it.Next()) != NULL;) + fOutputHeaders.AddHeader("Cookie", cookie->RawCookie(false)); } - + // Write output headers to output stream - for (int32 headerIndex = 0; - headerIndex < fOutputHeaders.CountHeaders(); - headerIndex++) + for (int32 headerIndex = 0; headerIndex < fOutputHeaders.CountHeaders(); + headerIndex++) _AddOutputBufferLine(fOutputHeaders.HeaderAt(headerIndex).Header()); } diff --git a/src/kits/network/libnetapi/UrlRequest.cpp b/src/kits/network/libnetapi/UrlRequest.cpp index 975cb48..4b30359 100644 --- a/src/kits/network/libnetapi/UrlRequest.cpp +++ b/src/kits/network/libnetapi/UrlRequest.cpp @@ -13,27 +13,15 @@ #include <Debug.h> -BUrlRequest::BUrlRequest(const BUrl& url, BUrlProtocolListener* listener) - : +BUrlRequest::BUrlRequest(const BUrl& url, BUrlProtocolListener* listener, + BUrlContext* context) + : fListener(listener), fUrlProtocol(NULL), fResult(url), - fContext(), + fContext(context), fUrl(), - fReady(false) -{ - SetUrl(url); -} - - -BUrlRequest::BUrlRequest(const BUrl& url) - : - fListener(NULL), - fUrlProtocol(NULL), - fResult(url), - fContext(), - fUrl(), - fReady(false) + fInitStatus(B_ERROR) { SetUrl(url); } @@ -46,12 +34,18 @@ BUrlRequest::BUrlRequest(const BUrlRequest& other) fResult(other.fUrl), fContext(), fUrl(), - fReady(false) + fInitStatus(B_ERROR) { *this = other; } +BUrlRequest::~BUrlRequest() +{ + if (fUrlProtocol != NULL) + delete fUrlProtocol; +} + // #pragma mark Request parameters modification @@ -60,16 +54,14 @@ BUrlRequest::SetUrl(const BUrl& url) { fUrl = url; fResult.SetUrl(url); - - if (fUrlProtocol != NULL && url.Protocol() == fUrl.Protocol()) + + if (fUrlProtocol != NULL && url.Protocol() == fUrl.Protocol()) { fUrlProtocol->SetUrl(url); - else { - status_t err = Identify(); - if (err != B_OK) - return err; + return B_OK; } - - return B_OK; + + fInitStatus = _SetupProtocol(); + return fInitStatus; } @@ -84,7 +76,7 @@ void BUrlRequest::SetProtocolListener(BUrlProtocolListener* listener) { fListener = listener; - + if (fUrlProtocol != NULL) fUrlProtocol->SetListener(listener); } @@ -95,7 +87,7 @@ BUrlRequest::SetProtocolOption(int32 option, void* value) { if (fUrlProtocol == NULL) return false; - + fUrlProtocol->SetOption(option, value); return true; } @@ -129,44 +121,18 @@ BUrlRequest::Url() status_t -BUrlRequest::Identify() -{ - // 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() +BUrlRequest::Start() { if (fUrlProtocol == NULL) { PRINT(("BUrlRequest::Perform() : Oops, no BUrlProtocol defined!\n")); return B_ERROR; } - + thread_id protocolThread = fUrlProtocol->Run(); - + if (protocolThread < B_OK) return protocolThread; - + return B_OK; } @@ -176,7 +142,7 @@ BUrlRequest::Pause() { if (fUrlProtocol == NULL) return B_ERROR; - + return fUrlProtocol->Pause(); } @@ -186,7 +152,7 @@ BUrlRequest::Resume() { if (fUrlProtocol == NULL) return B_ERROR; - + return fUrlProtocol->Resume(); } @@ -196,11 +162,11 @@ BUrlRequest::Abort() { if (fUrlProtocol == NULL) return B_ERROR; - + status_t returnCode = fUrlProtocol->Stop(); delete fUrlProtocol; fUrlProtocol = NULL; - + return returnCode; } @@ -208,10 +174,10 @@ BUrlRequest::Abort() // #pragma mark Request informations -bool +status_t BUrlRequest::InitCheck() const { - return fReady; + return fInitStatus; } @@ -220,7 +186,7 @@ BUrlRequest::IsRunning() const { if (fUrlProtocol == NULL) return false; - + return fUrlProtocol->IsRunning(); } @@ -230,7 +196,7 @@ BUrlRequest::Status() const { if (fUrlProtocol == NULL) return B_ERROR; - + return fUrlProtocol->Status(); } @@ -248,6 +214,29 @@ BUrlRequest::operator=(const BUrlRequest& other) fContext = other.fContext; fResult = BUrlResult(other.fUrl); SetUrl(other.fUrl); - + 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; +} diff --git a/src/kits/network/libnetapi/UrlSynchronousRequest.cpp b/src/kits/network/libnetapi/UrlSynchronousRequest.cpp index ae95424..2e819f4 100644 --- a/src/kits/network/libnetapi/UrlSynchronousRequest.cpp +++ b/src/kits/network/libnetapi/UrlSynchronousRequest.cpp @@ -14,7 +14,7 @@ BUrlSynchronousRequest::BUrlSynchronousRequest(BUrl& url) - : + : BUrlRequest(url, this), fRequestComplete(false) { @@ -26,8 +26,8 @@ BUrlSynchronousRequest::Perform() { SetProtocolListener(this); fRequestComplete = false; - - return BUrlRequest::Perform(); + + return Start(); } @@ -36,7 +36,7 @@ BUrlSynchronousRequest::WaitUntilCompletion() { while (!fRequestComplete) snooze(10000); - + return B_OK; } @@ -70,7 +70,7 @@ BUrlSynchronousRequest::HeadersReceived(BUrlProtocol*) void -BUrlSynchronousRequest::DataReceived(BUrlProtocol*, const char*, +BUrlSynchronousRequest::DataReceived(BUrlProtocol*, const char*, ssize_t size) { PRINT(("SynchronousRequest::DataReceived(%zd)\n", size)); @@ -78,7 +78,7 @@ BUrlSynchronousRequest::DataReceived(BUrlProtocol*, const char*, void -BUrlSynchronousRequest::DownloadProgress(BUrlProtocol*, +BUrlSynchronousRequest::DownloadProgress(BUrlProtocol*, ssize_t bytesReceived, ssize_t bytesTotal) { PRINT(("SynchronousRequest::DownloadProgress(%zd, %zd)\n", bytesReceived, @@ -98,7 +98,7 @@ BUrlSynchronousRequest::UploadProgress(BUrlProtocol*, ssize_t bytesSent, void 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()))); fRequestComplete = true; }