Clean code related to multiparts' Contents

This commit is contained in:
Sylvain Berfini 2018-03-23 10:37:31 +01:00
parent ba1d6bc8b0
commit 0dfd57b505
7 changed files with 65 additions and 151 deletions

View file

@ -419,6 +419,11 @@ SalBodyHandler * sal_body_handler_get_part(const SalBodyHandler *body_handler, i
return (SalBodyHandler *)belle_sip_list_nth_data(l, idx);
}
const belle_sip_list_t * sal_body_handler_get_parts(const SalBodyHandler *body_handler) {
if (!sal_body_handler_is_multipart(body_handler)) return NULL;
return belle_sip_multipart_body_handler_get_parts(BELLE_SIP_MULTIPART_BODY_HANDLER(body_handler));
}
SalBodyHandler * sal_body_handler_find_part_by_header(const SalBodyHandler *body_handler, const char *header_name, const char *header_value) {
const belle_sip_list_t *l = belle_sip_multipart_body_handler_get_parts(BELLE_SIP_MULTIPART_BODY_HANDLER(body_handler));
for (; l != NULL; l = l->next) {

View file

@ -647,6 +647,7 @@ size_t sal_body_handler_get_size(const SalBodyHandler *body_handler);
void sal_body_handler_set_size(SalBodyHandler *body_handler, size_t size);
bool_t sal_body_handler_is_multipart(const SalBodyHandler *body_handler);
SalBodyHandler * sal_body_handler_get_part(const SalBodyHandler *body_handler, int idx);
const belle_sip_list_t * sal_body_handler_get_parts(const SalBodyHandler *body_handler);
SalBodyHandler * sal_body_handler_find_part_by_header(const SalBodyHandler *body_handler, const char *header_name, const char *header_value);
const char * sal_body_handler_get_header(const SalBodyHandler *body_handler, const char *header_name);

View file

@ -20,14 +20,10 @@
// TODO: Remove me later.
#include "private.h"
#include "address/address.h"
#include "chat/chat-message/chat-message.h"
#include "chat/chat-room/chat-room.h"
#include "content/content-type.h"
#include "content/header-param.h"
#include "content/content-manager.h"
#include "content/file-transfer-content.h"
#include "logger/logger.h"
#include "core/core.h"
#include "multipart-chat-message-modifier.h"
@ -44,85 +40,30 @@ ChatMessageModifier::Result MultipartChatMessageModifier::encode (
if (message->getContents().size() <= 1)
return ChatMessageModifier::Result::Skipped;
LinphoneCore *lc = message->getChatRoom()->getCore()->getCCore();
char tmp[64];
lc->sal->create_uuid(tmp, sizeof(tmp));
string boundary = tmp;
stringstream multipartMessage;
multipartMessage << "--" << boundary;
for (Content *content : message->getContents()) {
multipartMessage << "\r\n";
multipartMessage << "Content-Type: " << content->getContentType().asString() << "\r\n\r\n";
multipartMessage << content->getBodyAsString() << "\r\n\r\n";
multipartMessage << "--" << boundary;
}
multipartMessage << "--";
Content newContent;
ContentType newContentType(ContentType::Multipart);
newContentType.addParameter("boundary", boundary);
newContent.setContentType(newContentType);
newContent.setBody(multipartMessage.str());
message->setInternalContent(newContent);
Content content = ContentManager::contentListToMultipart(message->getContents());
message->setInternalContent(content);
return ChatMessageModifier::Result::Done;
}
ChatMessageModifier::Result MultipartChatMessageModifier::decode (const shared_ptr<ChatMessage> &message, int &errorCode) {
if (message->getInternalContent().getContentType().getType() == "multipart") {
string boundary = message->getInternalContent().getContentType().getParameter("boundary").getValue();
if (boundary.empty()) {
lError() << "Boundary parameter of content-type not found: " << message->getInternalContent().getContentType().asString();
return ChatMessageModifier::Result::Error;
}
boundary = "--" + boundary;
lInfo() << "Multipart boundary is " << boundary;
const vector<char> body = message->getInternalContent().getBody();
string contentsString(body.begin(), body.end());
size_t pos = contentsString.find(boundary);
if (pos == string::npos) {
lError() << "Boundary not found in body !";
return ChatMessageModifier::Result::Error;
}
size_t start = pos + boundary.length() + 2; // 2 is the size of \r\n
size_t end;
do {
end = contentsString.find(boundary, start);
if (end != string::npos) {
string contentString = contentsString.substr(start, end - start);
size_t contentTypePos = contentString.find(": ") + 2; // 2 is the size of :
size_t endOfLinePos = contentString.find("\r\n");
if (contentTypePos >= endOfLinePos) {
lError() << "Content should start by a 'Content-Type: ' line !";
continue;
if (message->getInternalContent().getContentType().isMultipart()) {
for (Content &c : ContentManager::multipartToContentList(message->getInternalContent())) {
Content *content;
if (c.getContentType() == ContentType::FileTransfer) {
content = new FileTransferContent();
content->setContentType(c.getContentType());
content->setContentDisposition(c.getContentDisposition());
content->setContentEncoding(c.getContentEncoding());
for (const pair<string, string> &pair : c.getHeaders()) {
content->addHeader(pair.first, pair.second);
}
string contentTypeString = contentString.substr(contentTypePos, endOfLinePos - contentTypePos);
ContentType contentType(contentTypeString);
endOfLinePos += 4; // 4 is two time the size of \r\n
string contentBody = contentString.substr(endOfLinePos, contentString.length() - (endOfLinePos + 4)); // 4 is two time the size of \r\n
Content *content;
if (contentType == ContentType::FileTransfer) {
content = new FileTransferContent();
} else {
content = new Content();
}
content->setContentType(contentType);
content->setBody(contentBody);
message->addContent(content);
lInfo() << "Parsed and added content with type " << contentType.asString();
content->setBodyFromUtf8(c.getBodyAsUtf8String());
} else {
content = new Content(c);
}
start = end + boundary.length() + 2; // 2 is the size of \r\n
} while (end != string::npos);
message->addContent(content);
}
return ChatMessageModifier::Result::Done;
}
return ChatMessageModifier::Result::Skipped;

View file

@ -107,7 +107,7 @@ string LocalConferenceEventHandlerPrivate::createNotifyMultipart (int notifyId)
static_cast<unsigned int>(notifyId)
);
list<Content> contents;
list<Content *> contents;
for (const auto &eventLog : events) {
Content content;
content.setContentType(ContentType("application","conference-info"));
@ -181,7 +181,7 @@ string LocalConferenceEventHandlerPrivate::createNotifyMultipart (int notifyId)
continue;
}
content.setBody(body);
contents.push_back(content);
contents.push_back(&content);
}
if (contents.empty())

View file

@ -19,6 +19,10 @@
#include <belle-sip/belle-sip.h>
#include "c-wrapper/c-wrapper.h"
#include "linphone/api/c-content.h"
#include "content-manager.h"
#include "content-type.h"
#include "content/content.h"
@ -36,86 +40,47 @@ namespace {
// -----------------------------------------------------------------------------
list<Content> ContentManager::multipartToContentList (const Content &content) {
const string body = content.getBodyAsString();
belle_sip_multipart_body_handler_t *mpbh = belle_sip_multipart_body_handler_new_from_buffer(
body.c_str(), body.length(), MultipartBoundary
);
belle_sip_object_ref(mpbh);
LinphoneContent *cContent = L_GET_C_BACK_PTR(&content);
SalBodyHandler *sbh = sal_body_handler_ref(sal_body_handler_from_content(cContent));
list<Content> contents;
for (const belle_sip_list_t *parts = belle_sip_multipart_body_handler_get_parts(mpbh); parts; parts = parts->next) {
belle_sip_body_handler_t *part = BELLE_SIP_BODY_HANDLER(parts->data);
Content content;
for (const belle_sip_list_t *it = belle_sip_body_handler_get_headers(part); it; it = it->next) {
belle_sip_header_t *header = BELLE_SIP_HEADER(it->data);
if (strcasecmp("Content-Type", belle_sip_header_get_name(header)) == 0) {
belle_sip_header_content_type_t * partContentType = BELLE_SIP_HEADER_CONTENT_TYPE(header);
content.setContentType(ContentType(
belle_sip_header_content_type_get_type(partContentType),
belle_sip_header_content_type_get_subtype(partContentType)
));
} else {
content.addHeader(belle_sip_header_get_name(header), belle_sip_header_get_unparsed_value(header));
}
}
content.setBody(static_cast<const char *>(
belle_sip_memory_body_handler_get_buffer(BELLE_SIP_MEMORY_BODY_HANDLER(part))
));
contents.push_back(move(content));
for (const belle_sip_list_t *parts = sal_body_handler_get_parts(sbh); parts; parts = parts->next) {
SalBodyHandler *part = (SalBodyHandler *)parts->data;
LinphoneContent *cContent = linphone_content_from_sal_body_handler(part);
Content *cppContent = L_GET_CPP_PTR_FROM_C_OBJECT(cContent);
contents.push_back(*cppContent);
linphone_content_unref(cContent);
}
belle_sip_object_unref(mpbh);
sal_body_handler_unref(sbh);
linphone_content_unref(cContent);
return contents;
}
Content ContentManager::contentListToMultipart (const list<Content> &contents) {
Content ContentManager::contentListToMultipart (const list<Content *> &contents) {
belle_sip_multipart_body_handler_t *mpbh = belle_sip_multipart_body_handler_new(
nullptr, nullptr, nullptr, MultipartBoundary
);
belle_sip_object_ref(mpbh);
mpbh = (belle_sip_multipart_body_handler_t *)belle_sip_object_ref(mpbh);
for (const auto &content : contents) {
const ContentType &contentType = content.getContentType();
belle_sip_header_t *cContentType = BELLE_SIP_HEADER(
belle_sip_header_content_type_create(
contentType.getType().c_str(),
string(contentType.getSubType() + "; charset=\"UTF-8\"").c_str()
)
);
const string body = content.getBodyAsString();
belle_sip_memory_body_handler_t *mbh = belle_sip_memory_body_handler_new_copy_from_buffer(
body.c_str(), body.length(), nullptr, nullptr
);
belle_sip_body_handler_add_header(BELLE_SIP_BODY_HANDLER(mbh), cContentType);
for (const auto &header : content.getHeaders()) {
belle_sip_header_t *additionalHeader = BELLE_SIP_HEADER(
belle_sip_header_create(
header.first.c_str(),
header.second.c_str()
)
);
belle_sip_body_handler_add_header(BELLE_SIP_BODY_HANDLER(mbh), additionalHeader);
}
belle_sip_multipart_body_handler_add_part(mpbh, BELLE_SIP_BODY_HANDLER(mbh));
for (Content *content : contents) {
LinphoneContent *cContent = L_GET_C_BACK_PTR(content);
SalBodyHandler *sbh = sal_body_handler_from_content(cContent);
belle_sip_multipart_body_handler_add_part(mpbh, BELLE_SIP_BODY_HANDLER(sbh));
linphone_content_unref(cContent);
}
char *desc = belle_sip_object_to_string(mpbh);
Content content;
content.setBody(desc);
belle_sip_free(desc);
SalBodyHandler *sbh = (SalBodyHandler *)mpbh;
sal_body_handler_set_type(sbh, ContentType::Multipart.getType().c_str());
sal_body_handler_set_subtype(sbh, ContentType::Multipart.getSubType().c_str());
sal_body_handler_set_content_type_parameter(sbh, "boundary", MultipartBoundary);
LinphoneContent *cContent = linphone_content_from_sal_body_handler(sbh);
Content *content = L_GET_CPP_PTR_FROM_C_OBJECT(cContent);
Content returnContent = *content;
linphone_content_unref(cContent);
belle_sip_object_unref(mpbh);
ContentType contentType = ContentType::Multipart;
contentType.addParameter("boundary", string(MultipartBoundary));
content.setContentType(contentType);
return content;
return returnContent;
}
LINPHONE_END_NAMESPACE

View file

@ -32,7 +32,7 @@ class Content;
namespace ContentManager {
std::list<Content> multipartToContentList (const Content &content);
Content contentListToMultipart (const std::list<Content> &contents);
Content contentListToMultipart (const std::list<Content *> &contents);
}
LINPHONE_END_NAMESPACE

View file

@ -234,26 +234,28 @@ void multipart_to_list () {
generatedStr4.erase(std::remove(generatedStr4.begin(), generatedStr4.end(), '\r'), generatedStr4.end());
generatedStr4.erase(std::remove(generatedStr4.begin(), generatedStr4.end(), '\n'), generatedStr4.end());
ms_message("\n\n----- Generated part 4 -----");
ms_message("%s", generatedStr3.c_str());
ms_message("%s", generatedStr4.c_str());
ms_message("\n\n----- Original part 4 -----");
ms_message("%s", originalStr4.c_str());
BC_ASSERT_TRUE(originalStr4 == generatedStr4);
}
void list_to_multipart () {
ContentType contentType = ContentType("application", "rlmi+xml");
contentType.addParameter("charset", "\"UTF-8\"");
Content content1;
content1.setBody(part1);
content1.setContentType(ContentType("application", "rlmi+xml"));
content1.setContentType(contentType);
Content content2;
content2.setBody(part2);
content2.setContentType(ContentType("application", "pidf+xml"));
content2.setContentType(contentType);
Content content3;
content3.setBody(part3);
content3.setContentType(ContentType("application", "pidf+xml"));
content3.setContentType(contentType);
Content content4;
content4.setBody(part4);
content4.setContentType(ContentType("application", "pidf+xml"));
list<Content> contents = {content1, content2, content3, content4};
content4.setContentType(contentType);
list<Content *> contents = {&content1, &content2, &content3, &content4};
Content multipartContent = ContentManager::contentListToMultipart(contents);
string originalStr(multipart);