From 1221b2a95ac76111e906d3e8aae63fe9e46e05d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9gory=20Soutad=C3=A9?= Date: Thu, 17 Mar 2022 21:55:02 +0100 Subject: [PATCH] Add optional fd parameter to sendHTTPRequest() in order to directly write received data in a buffer and not in an intermediate buffer --- include/drmprocessorclient.h | 3 ++- include/libgourou.h | 9 +++++---- include/libgourou_common.h | 16 ++++++++++++++-- src/libgourou.cpp | 14 +++++++++----- utils/drmprocessorclientimpl.cpp | 27 +++++++++++++++++++++++---- utils/drmprocessorclientimpl.h | 2 +- utils/utils_common.cpp | 2 +- 7 files changed, 55 insertions(+), 18 deletions(-) diff --git a/include/drmprocessorclient.h b/include/drmprocessorclient.h index fc3b11a..7a28988 100644 --- a/include/drmprocessorclient.h +++ b/include/drmprocessorclient.h @@ -98,10 +98,11 @@ namespace gourou * @param POSTData POST data if needed, if not set, a GET request is done * @param contentType Optional content type of POST Data * @param responseHeaders Optional Response headers of HTTP request + * @param fd Optional file descriptor to write request result * * @return data of HTTP response */ - virtual std::string sendHTTPRequest(const std::string& URL, const std::string& POSTData=std::string(""), const std::string& contentType=std::string(""), std::map* responseHeaders=0) = 0; + virtual std::string sendHTTPRequest(const std::string& URL, const std::string& POSTData=std::string(""), const std::string& contentType=std::string(""), std::map* responseHeaders=0, int fd=0) = 0; }; class RSAInterface diff --git a/include/libgourou.h b/include/libgourou.h index bc5d61e..8146814 100644 --- a/include/libgourou.h +++ b/include/libgourou.h @@ -130,14 +130,15 @@ namespace gourou /** * @brief Send HTTP (GET or POST) request * - * @param URL HTTP URL - * @param POSTData POST data if needed, if not set, a GET request is done - * @param contentType Optional content type of POST Data + * @param URL HTTP URL + * @param POSTData POST data if needed, if not set, a GET request is done + * @param contentType Optional content type of POST Data * @param responseHeaders Optional Response headers of HTTP request + * @param fd Optional File descriptor to write received data * * @return data of HTTP response */ - ByteArray sendRequest(const std::string& URL, const std::string& POSTData=std::string(), const char* contentType=0, std::map* responseHeaders=0); + ByteArray sendRequest(const std::string& URL, const std::string& POSTData=std::string(), const char* contentType=0, std::map* responseHeaders=0, int fd=0); /** * @brief Send HTTP POST request to URL with document as POSTData diff --git a/include/libgourou_common.h b/include/libgourou_common.h index cc98de7..f640a9f 100644 --- a/include/libgourou_common.h +++ b/include/libgourou_common.h @@ -287,15 +287,27 @@ namespace gourou } /** - * @brief Write data in a file. If it already exists, it's truncated + * @brief Open a file descriptor on path. If it already exists, it's truncated + * + * @return Created fd, must be closed */ - static inline void writeFile(std::string path, const unsigned char* data, unsigned int length) + static inline int createNewFile(std::string path) { int fd = open(path.c_str(), O_CREAT|O_WRONLY|O_TRUNC, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH); if (fd <= 0) EXCEPTION(GOUROU_FILE_ERROR, "Unable to create " << path); + return fd; + } + + /** + * @brief Write data in a file. If it already exists, it's truncated + */ + static inline void writeFile(std::string path, const unsigned char* data, unsigned int length) + { + int fd = createNewFile(path); + if (write(fd, data, length) != length) EXCEPTION(GOUROU_FILE_ERROR, "Write error for file " << path); diff --git a/src/libgourou.cpp b/src/libgourou.cpp index cee9d9e..8fe2c63 100644 --- a/src/libgourou.cpp +++ b/src/libgourou.cpp @@ -300,12 +300,14 @@ namespace gourou appendTextElem(root, "adept:expiration", buffer); } - ByteArray DRMProcessor::sendRequest(const std::string& URL, const std::string& POSTdata, const char* contentType, std::map* responseHeaders) + ByteArray DRMProcessor::sendRequest(const std::string& URL, const std::string& POSTdata, const char* contentType, std::map* responseHeaders, int fd) { if (contentType == 0) contentType = ""; - std::string reply = client->sendHTTPRequest(URL, POSTdata, contentType, responseHeaders); + std::string reply = client->sendHTTPRequest(URL, POSTdata, contentType, responseHeaders, fd); + if (fd) return ByteArray(); + pugi::xml_document replyDoc; replyDoc.load_buffer(reply.c_str(), reply.length()); @@ -589,10 +591,12 @@ namespace gourou EXCEPTION(DW_NO_ITEM, "No item"); std::map headers; - - ByteArray replyData = sendRequest(item->getDownloadURL(), "", 0, &headers); - writeFile(path, replyData); + int fd = createNewFile(path); + + sendRequest(item->getDownloadURL(), "", 0, &headers, fd); + + close(fd); GOUROU_LOG(INFO, "Download into " << path); diff --git a/utils/drmprocessorclientimpl.cpp b/utils/drmprocessorclientimpl.cpp index f627275..a13941c 100644 --- a/utils/drmprocessorclientimpl.cpp +++ b/utils/drmprocessorclientimpl.cpp @@ -137,6 +137,17 @@ static size_t curlRead(void *data, size_t size, size_t nmemb, void *userp) return size*nmemb; } +static size_t curlReadFd(void *data, size_t size, size_t nmemb, void *userp) +{ + int fd = *(int*) userp; + + size_t res = write(fd, data, size*nmemb); + + downloadedBytes += res; + + return res; +} + static size_t curlHeaders(char *buffer, size_t size, size_t nitems, void *userdata) { std::map* responseHeaders = (std::map*)userdata; @@ -162,7 +173,7 @@ static size_t curlHeaders(char *buffer, size_t size, size_t nitems, void *userda return size*nitems; } -std::string DRMProcessorClientImpl::sendHTTPRequest(const std::string& URL, const std::string& POSTData, const std::string& contentType, std::map* responseHeaders) +std::string DRMProcessorClientImpl::sendHTTPRequest(const std::string& URL, const std::string& POSTData, const std::string& contentType, std::map* responseHeaders, int fd) { gourou::ByteArray replyData; std::map localHeaders; @@ -201,9 +212,17 @@ std::string DRMProcessorClientImpl::sendHTTPRequest(const std::string& URL, cons curl_easy_setopt(curl, CURLOPT_POSTFIELDS, POSTData.data()); } - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curlRead); - curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)&replyData); - + if (fd) + { + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curlReadFd); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)&fd); + } + else + { + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curlRead); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)&replyData); + } + curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, curlHeaders); curl_easy_setopt(curl, CURLOPT_HEADERDATA, (void*)responseHeaders); diff --git a/utils/drmprocessorclientimpl.h b/utils/drmprocessorclientimpl.h index 4913b05..d368f00 100644 --- a/utils/drmprocessorclientimpl.h +++ b/utils/drmprocessorclientimpl.h @@ -46,7 +46,7 @@ public: virtual void randBytes(unsigned char* bytesOut, unsigned int length); /* HTTP interface */ - virtual std::string sendHTTPRequest(const std::string& URL, const std::string& POSTData=std::string(""), const std::string& contentType=std::string(""), std::map* responseHeaders=0); + virtual std::string sendHTTPRequest(const std::string& URL, const std::string& POSTData=std::string(""), const std::string& contentType=std::string(""), std::map* responseHeaders=0, int fd=0); virtual void RSAPrivateEncrypt(const unsigned char* RSAKey, unsigned int RSAKeyLength, const RSA_KEY_TYPE keyType, const std::string& password, diff --git a/utils/utils_common.cpp b/utils/utils_common.cpp index 49b246d..c66af71 100644 --- a/utils/utils_common.cpp +++ b/utils/utils_common.cpp @@ -106,7 +106,7 @@ void fileCopy(const char* in, const char* out) if (!fdIn) EXCEPTION(gourou::CLIENT_FILE_ERROR, "Unable to open " << in); - fdOut = open(out, O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH); + fdOut = gourou::createNewFile(out); if (!fdOut) {