diff --git a/headers/os/net/DataRequest.h b/headers/os/net/DataRequest.h new file mode 100644 index 0000000000..9e5f546971 --- /dev/null +++ b/headers/os/net/DataRequest.h @@ -0,0 +1,29 @@ +/* + * Copyright 2013 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Adrien Destugues, pulkomandy@pulkomandy.tk + */ + + +#ifndef _B_DATA_REQUEST_H_ +#define _B_DATA_REQUEST_H_ + + +#include + + +class BDataRequest: public BUrlRequest { +public: + BDataRequest(const BUrl& url, + BUrlProtocolListener* listener = NULL, + BUrlContext* context = NULL); + const BUrlResult& Result() const; +private: + status_t _ProtocolLoop(); +private: + BUrlResult fResult; +}; + +#endif diff --git a/headers/os/net/FileRequest.h b/headers/os/net/FileRequest.h index 49c5974926..4ee8cf25d3 100644 --- a/headers/os/net/FileRequest.h +++ b/headers/os/net/FileRequest.h @@ -19,10 +19,13 @@ public: BUrlContext* context = NULL); virtual ~BFileRequest(); + const BUrlResult& Result() const; void SetDisableListener(bool disable); private: status_t _ProtocolLoop(); +private: + BUrlResult fResult; }; diff --git a/headers/os/net/HttpRequest.h b/headers/os/net/HttpRequest.h index 4573552987..3c0a77731d 100644 --- a/headers/os/net/HttpRequest.h +++ b/headers/os/net/HttpRequest.h @@ -47,7 +47,7 @@ public: const ssize_t size = -1); void AdoptHeaders(BHttpHeaders* const headers); - const BHttpResult& Result() const; + const BUrlResult& Result() const; const char* StatusString(status_t threadStatus) const; static bool IsInformationalStatusCode(int16 code); diff --git a/headers/os/net/HttpResult.h b/headers/os/net/HttpResult.h index 88f5de0e96..f2a6519b05 100644 --- a/headers/os/net/HttpResult.h +++ b/headers/os/net/HttpResult.h @@ -2,22 +2,22 @@ * Copyright 2010 Haiku Inc. All rights reserved. * Distributed under the terms of the MIT License. */ -#ifndef _B_URL_RESULT_H_ -#define _B_URL_RESULT_H_ +#ifndef _B_HTTP_RESULT_H_ +#define _B_HTTP_RESULT_H_ #include -#include #include #include #include +#include class BUrlRequest; -class BHttpResult { +class BHttpResult: public BUrlResult { friend class BHttpRequest; public: @@ -30,6 +30,8 @@ public: // Result parameters access const BUrl& Url() const; + BString ContentType() const; + size_t Length() const; // HTTP-Specific stuff const BHttpHeaders& Headers() const; @@ -45,7 +47,6 @@ public: private: BUrl fUrl; - // TODO: HTTP specific stuff should not live here. BHttpHeaders fHeaders; int32 fStatusCode; BString fStatusString; diff --git a/headers/os/net/UrlRequest.h b/headers/os/net/UrlRequest.h index b61b963383..8444ed8434 100644 --- a/headers/os/net/UrlRequest.h +++ b/headers/os/net/UrlRequest.h @@ -9,6 +9,7 @@ #include #include #include +#include #include @@ -43,6 +44,7 @@ public: status_t Status() const; virtual const char* StatusString(status_t threadStatus) const; + virtual const BUrlResult& Result() const = 0; protected: diff --git a/headers/os/net/UrlResult.h b/headers/os/net/UrlResult.h new file mode 100644 index 0000000000..c9beb00e20 --- /dev/null +++ b/headers/os/net/UrlResult.h @@ -0,0 +1,27 @@ +/* + * Copyright 2010 Haiku Inc. All rights reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef _B_URL_RESULT_H_ +#define _B_URL_RESULT_H_ + + +#include + + +class BUrlResult { +public: + virtual ~BUrlResult(); + void SetContentType(BString contentType); + void SetLength(size_t length); + + virtual BString ContentType() const; + virtual size_t Length() const; + +private: + BString fContentType; + BString fCharset; + size_t fLength; +}; + +#endif diff --git a/src/kits/network/libnetapi/DataRequest.cpp b/src/kits/network/libnetapi/DataRequest.cpp new file mode 100644 index 0000000000..20d7ad50c7 --- /dev/null +++ b/src/kits/network/libnetapi/DataRequest.cpp @@ -0,0 +1,106 @@ +/* + * Copyright 2013 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Adrien Destugues, pulkomandy@pulkomandy.tk + */ + + +#include "DataRequest.h" + +#include +#include +#include + + +BDataRequest::BDataRequest(const BUrl& url, BUrlProtocolListener* listener, + BUrlContext* context) + : BUrlRequest(url, listener, context, "data URL parser", "data"), + fResult() +{ + fResult.SetContentType("text/plain"); +} + + +const BUrlResult& +BDataRequest::Result() const +{ + return fResult; +} + + +status_t +BDataRequest::_ProtocolLoop() +{ + BString mimeType; + BString charset; + const char* payload; + size_t length; + bool isBase64 = false; + + fUrl.UrlDecode(true); + BString data = fUrl.Path(); + int separatorPosition = data.FindFirst(','); + + if (fListener != NULL) + fListener->ConnectionOpened(this); + + if (separatorPosition >= 0) { + BString meta = data; + meta.Truncate(separatorPosition); + data.Remove(0, separatorPosition + 1); + + int pos = 0; + while(meta.Length() > 0) + { + // Extract next parameter + pos = meta.FindFirst(';', pos); + + BString parameter = meta; + if(pos >= 0) { + parameter.Truncate(pos); + meta.Remove(0, pos+1); + } else + meta.Truncate(0); + + // Interpret the parameter + if(parameter == "base64") { + isBase64 = true; + } else if(parameter.FindFirst("charset=") == 0) { + charset = parameter; + } else { + // Must be the MIME type + mimeType = parameter; + } + } + + if (charset.Length() > 0) + mimeType << ";" << charset; + fResult.SetContentType(mimeType); + } + + if (isBase64) { + char* buffer = new char[data.Length() * 4 / 3]; + payload = buffer; + // payload must be a const char* so we can assign data.String() to + // it below, but decode_64 modifies buffer. + length = decode_base64(buffer, data.String(), data.Length()); + } else { + payload = data.String(); + length = data.Length(); + } + + fResult.SetLength(length); + + if (fListener != NULL) { + fListener->DownloadProgress(this, length, length); + if (length > 0) + fListener->DataReceived(this, payload, length); + } + + if (isBase64) + delete payload; + + return B_PROT_SUCCESS; +} diff --git a/src/kits/network/libnetapi/FileRequest.cpp b/src/kits/network/libnetapi/FileRequest.cpp index e295777514..21f087f400 100644 --- a/src/kits/network/libnetapi/FileRequest.cpp +++ b/src/kits/network/libnetapi/FileRequest.cpp @@ -7,19 +7,18 @@ */ -#include #include -#include - #include #include +#include BFileRequest::BFileRequest(const BUrl& url, BUrlProtocolListener* listener, BUrlContext* context) : - BUrlRequest(url, listener, context, "BUrlProtocol.File", "file") + BUrlRequest(url, listener, context, "BUrlProtocol.File", "file"), + fResult() { } @@ -29,6 +28,13 @@ BFileRequest::~BFileRequest() } +const BUrlResult& +BFileRequest::Result() const +{ + return fResult; +} + + status_t BFileRequest::_ProtocolLoop() { @@ -44,6 +50,7 @@ BFileRequest::_ProtocolLoop() off_t size = 0; file.GetSize(&size); fListener->DownloadProgress(this, size, size); + fResult.SetLength(size); ssize_t chunkSize; char chunk[4096]; @@ -51,5 +58,10 @@ BFileRequest::_ProtocolLoop() fListener->DataReceived(this, chunk, chunkSize); } + BNodeInfo info(&file); + char mimeType[B_MIME_TYPE_LENGTH + 1]; + if (info.GetType(mimeType) == B_OK) + fResult.SetContentType(mimeType); + return B_PROT_SUCCESS; } diff --git a/src/kits/network/libnetapi/HttpResult.cpp b/src/kits/network/libnetapi/HttpResult.cpp index 6e48505b73..6e61cec7b4 100644 --- a/src/kits/network/libnetapi/HttpResult.cpp +++ b/src/kits/network/libnetapi/HttpResult.cpp @@ -58,6 +58,23 @@ BHttpResult::Url() const } +BString +BHttpResult::ContentType() const +{ + return Headers()["Content-Type"]; +} + + +size_t +BHttpResult::Length() const +{ + const char* length = Headers()["Content-Length"]; + if (length == NULL) + return 0; + return atoi(length); +} + + const BHttpHeaders& BHttpResult::Headers() const { diff --git a/src/kits/network/libnetapi/Jamfile b/src/kits/network/libnetapi/Jamfile index 37d5272b54..ee0c66b524 100644 --- a/src/kits/network/libnetapi/Jamfile +++ b/src/kits/network/libnetapi/Jamfile @@ -55,6 +55,7 @@ for architectureObject in [ MultiArchSubDirSetup ] { # TODO: The HTTP stuff should all go into an add-on. It needs # linking against libcrypto.so and only the add-on should link # against it. + DataRequest.cpp HttpAuthentication.cpp HttpHeaders.cpp HttpForm.cpp @@ -74,6 +75,7 @@ for architectureObject in [ MultiArchSubDirSetup ] { UrlProtocolListener.cpp UrlProtocolRoster.cpp UrlRequest.cpp + UrlResult.cpp UrlSynchronousRequest.cpp : diff --git a/src/kits/network/libnetapi/UrlProtocolRoster.cpp b/src/kits/network/libnetapi/UrlProtocolRoster.cpp index 0fc76b5e2e..17018bf362 100644 --- a/src/kits/network/libnetapi/UrlProtocolRoster.cpp +++ b/src/kits/network/libnetapi/UrlProtocolRoster.cpp @@ -11,10 +11,11 @@ #include -#include +#include +#include #include #include -#include +#include static BUrlContext gDefaultContext; @@ -36,6 +37,8 @@ BUrlProtocolRoster::MakeRequest(const BUrl& url, context); } else if (url.Protocol() == "file") { return new(std::nothrow) BFileRequest(url, listener, context); + } else if (url.Protocol() == "data") { + return new(std::nothrow) BDataRequest(url, listener, context); } return NULL; diff --git a/src/kits/network/libnetapi/UrlResult.cpp b/src/kits/network/libnetapi/UrlResult.cpp new file mode 100644 index 0000000000..67191a2da8 --- /dev/null +++ b/src/kits/network/libnetapi/UrlResult.cpp @@ -0,0 +1,43 @@ +/* + * Copyright 2013 Haiku Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Adrien Destugues, pulkomandy@pulkomandy.tk + */ + + +#include + + +BUrlResult::~BUrlResult() +{ +} + + +void +BUrlResult::SetContentType(BString contentType) +{ + fContentType = contentType; +} + + +void +BUrlResult::SetLength(size_t length) +{ + fLength = length; +} + + +BString +BUrlResult::ContentType() const +{ + return fContentType; +} + + +size_t +BUrlResult::Length() const +{ + return fLength; +}