[Media] Nuke unused llmime and associated build tests, also remove unneeded includes in llmimetypes header.
This commit is contained in:
@@ -64,7 +64,6 @@ set(llmessage_SOURCE_FILES
|
|||||||
llmessagetemplate.cpp
|
llmessagetemplate.cpp
|
||||||
llmessagetemplateparser.cpp
|
llmessagetemplateparser.cpp
|
||||||
llmessagethrottle.cpp
|
llmessagethrottle.cpp
|
||||||
llmime.cpp
|
|
||||||
llnamevalue.cpp
|
llnamevalue.cpp
|
||||||
llnullcipher.cpp
|
llnullcipher.cpp
|
||||||
llpacketack.cpp
|
llpacketack.cpp
|
||||||
@@ -163,7 +162,6 @@ set(llmessage_HEADER_FILES
|
|||||||
llmessagetemplate.h
|
llmessagetemplate.h
|
||||||
llmessagetemplateparser.h
|
llmessagetemplateparser.h
|
||||||
llmessagethrottle.h
|
llmessagethrottle.h
|
||||||
llmime.h
|
|
||||||
llmsgvariabletype.h
|
llmsgvariabletype.h
|
||||||
llnamevalue.h
|
llnamevalue.h
|
||||||
llnullcipher.h
|
llnullcipher.h
|
||||||
@@ -241,7 +239,6 @@ if (LL_TESTS)
|
|||||||
include(Tut)
|
include(Tut)
|
||||||
|
|
||||||
SET(llmessage_TEST_SOURCE_FILES
|
SET(llmessage_TEST_SOURCE_FILES
|
||||||
llmime.cpp
|
|
||||||
llnamevalue.cpp
|
llnamevalue.cpp
|
||||||
lltrustedmessageservice.cpp
|
lltrustedmessageservice.cpp
|
||||||
lltemplatemessagedispatcher.cpp
|
lltemplatemessagedispatcher.cpp
|
||||||
|
|||||||
@@ -1,629 +0,0 @@
|
|||||||
/**
|
|
||||||
* @file llmime.cpp
|
|
||||||
* @author Phoenix
|
|
||||||
* @date 2006-12-20
|
|
||||||
* @brief Implementation of mime tools.
|
|
||||||
*
|
|
||||||
* $LicenseInfo:firstyear=2006&license=viewerlgpl$
|
|
||||||
* Second Life Viewer Source Code
|
|
||||||
* Copyright (C) 2010, Linden Research, Inc.
|
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
|
||||||
* License as published by the Free Software Foundation;
|
|
||||||
* version 2.1 of the License only.
|
|
||||||
*
|
|
||||||
* This library is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
* Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with this library; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*
|
|
||||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
|
||||||
* $/LicenseInfo$
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "linden_common.h"
|
|
||||||
#include "llmime.h"
|
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include "llmemorystream.h"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Useful constants.
|
|
||||||
*/
|
|
||||||
// Headers specified in rfc-2045 will be canonicalized below.
|
|
||||||
static const std::string CONTENT_LENGTH("Content-Length");
|
|
||||||
static const std::string CONTENT_TYPE("Content-Type");
|
|
||||||
static const S32 KNOWN_HEADER_COUNT = 6;
|
|
||||||
static const std::string KNOWN_HEADER[KNOWN_HEADER_COUNT] =
|
|
||||||
{
|
|
||||||
CONTENT_LENGTH,
|
|
||||||
CONTENT_TYPE,
|
|
||||||
std::string("MIME-Version"),
|
|
||||||
std::string("Content-Transfer-Encoding"),
|
|
||||||
std::string("Content-ID"),
|
|
||||||
std::string("Content-Description"),
|
|
||||||
};
|
|
||||||
|
|
||||||
// parser helpers
|
|
||||||
static const std::string MULTIPART("multipart");
|
|
||||||
static const std::string BOUNDARY("boundary");
|
|
||||||
static const std::string END_OF_CONTENT_PARAMETER("\r\n ;\t");
|
|
||||||
static const std::string SEPARATOR_PREFIX("--");
|
|
||||||
//static const std::string SEPARATOR_SUFFIX("\r\n");
|
|
||||||
|
|
||||||
/*
|
|
||||||
Content-Type: multipart/mixed; boundary="segment"
|
|
||||||
Content-Length: 24832
|
|
||||||
|
|
||||||
--segment
|
|
||||||
Content-Type: image/j2c
|
|
||||||
Content-Length: 23715
|
|
||||||
|
|
||||||
<data>
|
|
||||||
|
|
||||||
--segment
|
|
||||||
Content-Type: text/xml; charset=UTF-8
|
|
||||||
|
|
||||||
<meta data>
|
|
||||||
EOF
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* LLMimeIndex
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @class LLMimeIndex::Impl
|
|
||||||
* @brief Implementation details of the mime index class.
|
|
||||||
* @see LLMimeIndex
|
|
||||||
*/
|
|
||||||
class LLMimeIndex::Impl
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
Impl() : mOffset(-1), mUseCount(1)
|
|
||||||
{}
|
|
||||||
Impl(LLSD headers, S32 offset) :
|
|
||||||
mHeaders(headers), mOffset(offset), mUseCount(1)
|
|
||||||
{}
|
|
||||||
public:
|
|
||||||
LLSD mHeaders;
|
|
||||||
S32 mOffset;
|
|
||||||
S32 mUseCount;
|
|
||||||
|
|
||||||
typedef std::vector<LLMimeIndex> sub_part_t;
|
|
||||||
sub_part_t mAttachments;
|
|
||||||
};
|
|
||||||
|
|
||||||
LLSD LLMimeIndex::headers() const
|
|
||||||
{
|
|
||||||
return mImpl->mHeaders;
|
|
||||||
}
|
|
||||||
|
|
||||||
S32 LLMimeIndex::offset() const
|
|
||||||
{
|
|
||||||
return mImpl->mOffset;
|
|
||||||
}
|
|
||||||
|
|
||||||
S32 LLMimeIndex::contentLength() const
|
|
||||||
{
|
|
||||||
// Find the content length in the headers.
|
|
||||||
S32 length = -1;
|
|
||||||
LLSD content_length = mImpl->mHeaders[CONTENT_LENGTH];
|
|
||||||
if(content_length.isDefined())
|
|
||||||
{
|
|
||||||
length = content_length.asInteger();
|
|
||||||
}
|
|
||||||
return length;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string LLMimeIndex::contentType() const
|
|
||||||
{
|
|
||||||
std::string type;
|
|
||||||
LLSD content_type = mImpl->mHeaders[CONTENT_TYPE];
|
|
||||||
if(content_type.isDefined())
|
|
||||||
{
|
|
||||||
type = content_type.asString();
|
|
||||||
}
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool LLMimeIndex::isMultipart() const
|
|
||||||
{
|
|
||||||
bool multipart = false;
|
|
||||||
LLSD content_type = mImpl->mHeaders[CONTENT_TYPE];
|
|
||||||
if(content_type.isDefined())
|
|
||||||
{
|
|
||||||
std::string type = content_type.asString();
|
|
||||||
int comp = type.compare(0, MULTIPART.size(), MULTIPART);
|
|
||||||
if(0 == comp)
|
|
||||||
{
|
|
||||||
multipart = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return multipart;
|
|
||||||
}
|
|
||||||
|
|
||||||
S32 LLMimeIndex::subPartCount() const
|
|
||||||
{
|
|
||||||
return mImpl->mAttachments.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
LLMimeIndex LLMimeIndex::subPart(S32 index) const
|
|
||||||
{
|
|
||||||
LLMimeIndex part;
|
|
||||||
if((index >= 0) && (index < (S32)mImpl->mAttachments.size()))
|
|
||||||
{
|
|
||||||
part = mImpl->mAttachments[index];
|
|
||||||
}
|
|
||||||
return part;
|
|
||||||
}
|
|
||||||
|
|
||||||
LLMimeIndex::LLMimeIndex() : mImpl(new LLMimeIndex::Impl)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
LLMimeIndex::LLMimeIndex(LLSD headers, S32 content_offset) :
|
|
||||||
mImpl(new LLMimeIndex::Impl(headers, content_offset))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
LLMimeIndex::LLMimeIndex(const LLMimeIndex& mime) :
|
|
||||||
mImpl(mime.mImpl)
|
|
||||||
{
|
|
||||||
++mImpl->mUseCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
LLMimeIndex::~LLMimeIndex()
|
|
||||||
{
|
|
||||||
if(0 == --mImpl->mUseCount)
|
|
||||||
{
|
|
||||||
delete mImpl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
LLMimeIndex& LLMimeIndex::operator=(const LLMimeIndex& mime)
|
|
||||||
{
|
|
||||||
// Increment use count first so that we handle self assignment
|
|
||||||
// automatically.
|
|
||||||
++mime.mImpl->mUseCount;
|
|
||||||
if(0 == --mImpl->mUseCount)
|
|
||||||
{
|
|
||||||
delete mImpl;
|
|
||||||
}
|
|
||||||
mImpl = mime.mImpl;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool LLMimeIndex::attachSubPart(LLMimeIndex sub_part)
|
|
||||||
{
|
|
||||||
// *FIX: Should we check for multi-part?
|
|
||||||
if(mImpl->mAttachments.size() < S32_MAX)
|
|
||||||
{
|
|
||||||
mImpl->mAttachments.push_back(sub_part);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* LLMimeParser
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* @class LLMimeParser::Impl
|
|
||||||
* @brief Implementation details of the mime parser class.
|
|
||||||
* @see LLMimeParser
|
|
||||||
*/
|
|
||||||
class LLMimeParser::Impl
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
// @brief Constructor.
|
|
||||||
Impl();
|
|
||||||
|
|
||||||
// @brief Reset this for a new parse.
|
|
||||||
void reset();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Parse a mime entity to find the index information.
|
|
||||||
*
|
|
||||||
* This method will scan the istr until a single complete mime
|
|
||||||
* entity is read, an EOF, or limit bytes have been scanned. The
|
|
||||||
* istr will be modified by this parsing, so pass in a temporary
|
|
||||||
* stream or rewind/reset the stream after this call.
|
|
||||||
* @param istr An istream which contains a mime entity.
|
|
||||||
* @param limit The maximum number of bytes to scan.
|
|
||||||
* @param separator The multipart separator if it is known.
|
|
||||||
* @param is_subpart Set true if parsing a multipart sub part.
|
|
||||||
* @param index[out] The parsed output.
|
|
||||||
* @return Returns true if an index was parsed and no errors occurred.
|
|
||||||
*/
|
|
||||||
bool parseIndex(
|
|
||||||
std::istream& istr,
|
|
||||||
S32 limit,
|
|
||||||
const std::string& separator,
|
|
||||||
bool is_subpart,
|
|
||||||
LLMimeIndex& index);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
/**
|
|
||||||
* @brief parse the headers.
|
|
||||||
*
|
|
||||||
* At the end of a successful parse, mScanCount will be at the
|
|
||||||
* start of the content.
|
|
||||||
* @param istr The input stream.
|
|
||||||
* @param limit maximum number of bytes to process
|
|
||||||
* @param headers[out] A map of the headers found.
|
|
||||||
* @return Returns true if the parse was successful.
|
|
||||||
*/
|
|
||||||
bool parseHeaders(std::istream& istr, S32 limit, LLSD& headers);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Figure out the separator string from a content type header.
|
|
||||||
*
|
|
||||||
* @param multipart_content_type The content type value from the headers.
|
|
||||||
* @return Returns the separator string.
|
|
||||||
*/
|
|
||||||
std::string findSeparator(std::string multipart_content_type);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Scan through istr past the separator.
|
|
||||||
*
|
|
||||||
* @param istr The input stream.
|
|
||||||
* @param limit Maximum number of bytes to scan.
|
|
||||||
* @param separator The multipart separator.
|
|
||||||
*/
|
|
||||||
void scanPastSeparator(
|
|
||||||
std::istream& istr,
|
|
||||||
S32 limit,
|
|
||||||
const std::string& separator);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Scan through istr past the content of the current mime part.
|
|
||||||
*
|
|
||||||
* @param istr The input stream.
|
|
||||||
* @param limit Maximum number of bytes to scan.
|
|
||||||
* @param headers The headers for this mime part.
|
|
||||||
* @param separator The multipart separator if known.
|
|
||||||
*/
|
|
||||||
void scanPastContent(
|
|
||||||
std::istream& istr,
|
|
||||||
S32 limit,
|
|
||||||
LLSD headers,
|
|
||||||
const std::string separator);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Eat CRLF.
|
|
||||||
*
|
|
||||||
* This method has no concept of the limit, so ensure you have at
|
|
||||||
* least 2 characters left to eat before hitting the limit. This
|
|
||||||
* method will increment mScanCount as it goes.
|
|
||||||
* @param istr The input stream.
|
|
||||||
* @return Returns true if CRLF was found and consumed off of istr.
|
|
||||||
*/
|
|
||||||
bool eatCRLF(std::istream& istr);
|
|
||||||
|
|
||||||
// @brief Returns true if parsing should continue.
|
|
||||||
bool continueParse() const { return (!mError && mContinue); }
|
|
||||||
|
|
||||||
// @brief anonymous enumeration for parse buffer size.
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
LINE_BUFFER_LENGTH = 1024
|
|
||||||
};
|
|
||||||
|
|
||||||
protected:
|
|
||||||
S32 mScanCount;
|
|
||||||
bool mContinue;
|
|
||||||
bool mError;
|
|
||||||
char mBuffer[LINE_BUFFER_LENGTH];
|
|
||||||
};
|
|
||||||
|
|
||||||
LLMimeParser::Impl::Impl()
|
|
||||||
{
|
|
||||||
reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
void LLMimeParser::Impl::reset()
|
|
||||||
{
|
|
||||||
mScanCount = 0;
|
|
||||||
mContinue = true;
|
|
||||||
mError = false;
|
|
||||||
mBuffer[0] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
bool LLMimeParser::Impl::parseIndex(
|
|
||||||
std::istream& istr,
|
|
||||||
S32 limit,
|
|
||||||
const std::string& separator,
|
|
||||||
bool is_subpart,
|
|
||||||
LLMimeIndex& index)
|
|
||||||
{
|
|
||||||
LLSD headers;
|
|
||||||
bool parsed_something = false;
|
|
||||||
if(parseHeaders(istr, limit, headers))
|
|
||||||
{
|
|
||||||
parsed_something = true;
|
|
||||||
LLMimeIndex mime(headers, mScanCount);
|
|
||||||
index = mime;
|
|
||||||
if(index.isMultipart())
|
|
||||||
{
|
|
||||||
// Figure out the separator, scan past it, and recurse.
|
|
||||||
std::string ct = headers[CONTENT_TYPE].asString();
|
|
||||||
std::string sep = findSeparator(ct);
|
|
||||||
scanPastSeparator(istr, limit, sep);
|
|
||||||
while(continueParse() && parseIndex(istr, limit, sep, true, mime))
|
|
||||||
{
|
|
||||||
index.attachSubPart(mime);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Scan to the end of content.
|
|
||||||
scanPastContent(istr, limit, headers, separator);
|
|
||||||
if(is_subpart)
|
|
||||||
{
|
|
||||||
scanPastSeparator(istr, limit, separator);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(mError) return false;
|
|
||||||
return parsed_something;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool LLMimeParser::Impl::parseHeaders(
|
|
||||||
std::istream& istr,
|
|
||||||
S32 limit,
|
|
||||||
LLSD& headers)
|
|
||||||
{
|
|
||||||
while(continueParse())
|
|
||||||
{
|
|
||||||
// Get the next line.
|
|
||||||
// We subtract 1 from the limit so that we make sure
|
|
||||||
// not to read past limit when we get() the newline.
|
|
||||||
S32 max_get = llmin((S32)LINE_BUFFER_LENGTH, limit - mScanCount - 1);
|
|
||||||
istr.getline(mBuffer, max_get, '\r');
|
|
||||||
mScanCount += (S32)istr.gcount();
|
|
||||||
int c = istr.get();
|
|
||||||
if(EOF == c)
|
|
||||||
{
|
|
||||||
mContinue = false;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
++mScanCount;
|
|
||||||
if(c != '\n')
|
|
||||||
{
|
|
||||||
mError = true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if(mScanCount >= limit)
|
|
||||||
{
|
|
||||||
mContinue = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if that's the end of headers.
|
|
||||||
if('\0' == mBuffer[0])
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Split out the name and value.
|
|
||||||
// *NOTE: The use of strchr() here is safe since mBuffer is
|
|
||||||
// guaranteed to be NULL terminated from the call to getline()
|
|
||||||
// above.
|
|
||||||
char* colon = strchr(mBuffer, ':');
|
|
||||||
if(!colon)
|
|
||||||
{
|
|
||||||
mError = true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cononicalize the name part, and store the name: value in
|
|
||||||
// the headers structure. We do this by iterating through
|
|
||||||
// 'known' headers and replacing the value found with the
|
|
||||||
// correct one.
|
|
||||||
// *NOTE: Not so efficient, but iterating through a small
|
|
||||||
// subset should not be too much of an issue.
|
|
||||||
std::string name(mBuffer, colon++ - mBuffer);
|
|
||||||
while(isspace(*colon)) ++colon;
|
|
||||||
std::string value(colon);
|
|
||||||
for(S32 ii = 0; ii < KNOWN_HEADER_COUNT; ++ii)
|
|
||||||
{
|
|
||||||
if(0 == LLStringUtil::compareInsensitive(name, KNOWN_HEADER[ii]))
|
|
||||||
{
|
|
||||||
name = KNOWN_HEADER[ii];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
headers[name] = value;
|
|
||||||
}
|
|
||||||
if(headers.isUndefined()) return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string LLMimeParser::Impl::findSeparator(std::string header)
|
|
||||||
{
|
|
||||||
// 01234567890
|
|
||||||
//Content-Type: multipart/mixed; boundary="segment"
|
|
||||||
std::string separator;
|
|
||||||
std::string::size_type pos = header.find(BOUNDARY);
|
|
||||||
if(std::string::npos == pos) return separator;
|
|
||||||
pos += BOUNDARY.size() + 1;
|
|
||||||
std::string::size_type end;
|
|
||||||
if(header[pos] == '"')
|
|
||||||
{
|
|
||||||
// the boundary is quoted, find the end from pos, and take the
|
|
||||||
// substring.
|
|
||||||
end = header.find('"', ++pos);
|
|
||||||
if(std::string::npos == end)
|
|
||||||
{
|
|
||||||
// poorly formed boundary.
|
|
||||||
mError = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// otherwise, it's every character until a whitespace, end of
|
|
||||||
// line, or another parameter begins.
|
|
||||||
end = header.find_first_of(END_OF_CONTENT_PARAMETER, pos);
|
|
||||||
if(std::string::npos == end)
|
|
||||||
{
|
|
||||||
// it goes to the end of the string.
|
|
||||||
end = header.size();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(!mError) separator = header.substr(pos, end - pos);
|
|
||||||
return separator;
|
|
||||||
}
|
|
||||||
|
|
||||||
void LLMimeParser::Impl::scanPastSeparator(
|
|
||||||
std::istream& istr,
|
|
||||||
S32 limit,
|
|
||||||
const std::string& sep)
|
|
||||||
{
|
|
||||||
std::ostringstream ostr;
|
|
||||||
ostr << SEPARATOR_PREFIX << sep;
|
|
||||||
std::string separator = ostr.str();
|
|
||||||
bool found_separator = false;
|
|
||||||
while(!found_separator && continueParse())
|
|
||||||
{
|
|
||||||
// Subtract 1 from the limit so that we make sure not to read
|
|
||||||
// past limit when we get() the newline.
|
|
||||||
S32 max_get = llmin((S32)LINE_BUFFER_LENGTH, limit - mScanCount - 1);
|
|
||||||
istr.getline(mBuffer, max_get, '\r');
|
|
||||||
mScanCount += (S32)istr.gcount();
|
|
||||||
if(istr.gcount() >= LINE_BUFFER_LENGTH - 1)
|
|
||||||
{
|
|
||||||
// that's way too long to be a separator, so ignore it.
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
int c = istr.get();
|
|
||||||
if(EOF == c)
|
|
||||||
{
|
|
||||||
mContinue = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
++mScanCount;
|
|
||||||
if(c != '\n')
|
|
||||||
{
|
|
||||||
mError = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if(mScanCount >= limit)
|
|
||||||
{
|
|
||||||
mContinue = false;
|
|
||||||
}
|
|
||||||
if(0 == LLStringUtil::compareStrings(std::string(mBuffer), separator))
|
|
||||||
{
|
|
||||||
found_separator = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void LLMimeParser::Impl::scanPastContent(
|
|
||||||
std::istream& istr,
|
|
||||||
S32 limit,
|
|
||||||
LLSD headers,
|
|
||||||
const std::string separator)
|
|
||||||
{
|
|
||||||
if(headers.has(CONTENT_LENGTH))
|
|
||||||
{
|
|
||||||
S32 content_length = headers[CONTENT_LENGTH].asInteger();
|
|
||||||
// Subtract 2 here for the \r\n after the content.
|
|
||||||
S32 max_skip = llmin(content_length, limit - mScanCount - 2);
|
|
||||||
istr.ignore(max_skip);
|
|
||||||
mScanCount += max_skip;
|
|
||||||
|
|
||||||
// *NOTE: Check for hitting the limit and eof here before
|
|
||||||
// checking for the trailing EOF, because our mime parser has
|
|
||||||
// to gracefully handle incomplete mime entites.
|
|
||||||
if((mScanCount >= limit) || istr.eof())
|
|
||||||
{
|
|
||||||
mContinue = false;
|
|
||||||
}
|
|
||||||
else if(!eatCRLF(istr))
|
|
||||||
{
|
|
||||||
mError = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool LLMimeParser::Impl::eatCRLF(std::istream& istr)
|
|
||||||
{
|
|
||||||
int c = istr.get();
|
|
||||||
++mScanCount;
|
|
||||||
if(c != '\r')
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
c = istr.get();
|
|
||||||
++mScanCount;
|
|
||||||
if(c != '\n')
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
LLMimeParser::LLMimeParser() : mImpl(* new LLMimeParser::Impl)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
LLMimeParser::~LLMimeParser()
|
|
||||||
{
|
|
||||||
delete & mImpl;
|
|
||||||
}
|
|
||||||
|
|
||||||
void LLMimeParser::reset()
|
|
||||||
{
|
|
||||||
mImpl.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool LLMimeParser::parseIndex(std::istream& istr, LLMimeIndex& index)
|
|
||||||
{
|
|
||||||
std::string separator;
|
|
||||||
return mImpl.parseIndex(istr, S32_MAX, separator, false, index);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool LLMimeParser::parseIndex(
|
|
||||||
const std::vector<U8>& buffer,
|
|
||||||
LLMimeIndex& index)
|
|
||||||
{
|
|
||||||
LLMemoryStream mstr(&buffer[0], buffer.size());
|
|
||||||
return parseIndex(mstr, buffer.size() + 1, index);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool LLMimeParser::parseIndex(
|
|
||||||
std::istream& istr,
|
|
||||||
S32 limit,
|
|
||||||
LLMimeIndex& index)
|
|
||||||
{
|
|
||||||
std::string separator;
|
|
||||||
return mImpl.parseIndex(istr, limit, separator, false, index);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool LLMimeParser::parseIndex(const U8* buffer, S32 length, LLMimeIndex& index)
|
|
||||||
{
|
|
||||||
LLMemoryStream mstr(buffer, length);
|
|
||||||
return parseIndex(mstr, length + 1, index);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
bool LLMimeParser::verify(std::istream& isr, LLMimeIndex& index) const
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool LLMimeParser::verify(U8* buffer, S32 length, LLMimeIndex& index) const
|
|
||||||
{
|
|
||||||
LLMemoryStream mstr(buffer, length);
|
|
||||||
return verify(mstr, index);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
@@ -1,292 +0,0 @@
|
|||||||
/**
|
|
||||||
* @file llmime.h
|
|
||||||
* @author Phoenix
|
|
||||||
* @date 2006-12-20
|
|
||||||
* @brief Declaration of mime tools.
|
|
||||||
*
|
|
||||||
* $LicenseInfo:firstyear=2006&license=viewerlgpl$
|
|
||||||
* Second Life Viewer Source Code
|
|
||||||
* Copyright (C) 2010, Linden Research, Inc.
|
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
|
||||||
* License as published by the Free Software Foundation;
|
|
||||||
* version 2.1 of the License only.
|
|
||||||
*
|
|
||||||
* This library is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
* Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with this library; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*
|
|
||||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
|
||||||
* $/LicenseInfo$
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef LL_LLMIME_H
|
|
||||||
#define LL_LLMIME_H
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include "llsd.h"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This file declares various tools for parsing and creating MIME
|
|
||||||
* objects as described in RFCs 2045, 2046, 2047, 2048, and 2049.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @class LLMimeIndex
|
|
||||||
* @brief Skeletal information useful for handling mime packages.
|
|
||||||
* @see LLMimeParser
|
|
||||||
*
|
|
||||||
* An instance of this class is the parsed output from a LLMimeParser
|
|
||||||
* which then allows for easy access into a data stream to find and
|
|
||||||
* get what you want out of it.
|
|
||||||
*
|
|
||||||
* This class meant as a tool to quickly find what you seek in a
|
|
||||||
* parsed mime entity. As such, it does not have useful support for
|
|
||||||
* modification of a mime entity and specializes the interface toward
|
|
||||||
* querying data from a fixed mime entity. Modifying an instance of
|
|
||||||
* LLMimeIndx does not alter a mime entity and changes to a mime
|
|
||||||
* entity itself are not propogated into an instance of a LLMimeIndex.
|
|
||||||
*
|
|
||||||
* Usage:<br>
|
|
||||||
* LLMimeIndex mime_index;<br>
|
|
||||||
* std::ifstream fstr("package.mime", ios::binary);<br>
|
|
||||||
* LLMimeParser parser;<br>
|
|
||||||
* if(parser.parseIndex(fstr, mime_index))<br>
|
|
||||||
* {<br>
|
|
||||||
* std::vector<U8> content;<br>
|
|
||||||
* content.resize(mime_index.contentLength());<br>
|
|
||||||
* fstr.seekg(mime_index.offset(), ios::beg);<br>
|
|
||||||
* // ...do work on fstr and content<br>
|
|
||||||
* }<br>
|
|
||||||
*/
|
|
||||||
class LLMimeIndex
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
/* @name Client interface.
|
|
||||||
*/
|
|
||||||
//@{
|
|
||||||
/**
|
|
||||||
* @brief Get the full parsed headers for this.
|
|
||||||
*
|
|
||||||
* If there are any headers, it will be a map of header name to
|
|
||||||
* the value found on the line. The name is everything before the
|
|
||||||
* colon, and the value is the string found after the colon to the
|
|
||||||
* end of the line after trimming leading whitespace. So, for
|
|
||||||
* example:
|
|
||||||
* Content-Type: text/plain
|
|
||||||
* would become an entry in the headers of:
|
|
||||||
* headers["Content-Type"] == "text/plain"
|
|
||||||
*
|
|
||||||
* If this instance of an index was generated by the
|
|
||||||
* LLMimeParser::parseIndex() call, all header names in rfc2045
|
|
||||||
* will be capitalized as in rfc, eg Content-Length and
|
|
||||||
* MIME-Version, not content-length and mime-version.
|
|
||||||
* @return Returns an LLSD map of header name to value. Returns
|
|
||||||
* undef if there are no headers.
|
|
||||||
*/
|
|
||||||
LLSD headers() const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Get the content offset.
|
|
||||||
*
|
|
||||||
* @return Returns the number of bytes to the start of the data
|
|
||||||
* segment from the start of serialized mime entity. Returns -1 if
|
|
||||||
* offset is not known.
|
|
||||||
*/
|
|
||||||
S32 offset() const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Get the length of the data segment for this mime part.
|
|
||||||
*
|
|
||||||
* @return Returns the content length in bytes. Returns -1 if
|
|
||||||
* length is not known.
|
|
||||||
*/
|
|
||||||
S32 contentLength() const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Get the mime type associated with this node.
|
|
||||||
*
|
|
||||||
* @return Returns the mimetype.
|
|
||||||
*/
|
|
||||||
std::string contentType() const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Helper method which simplifies parsing the return from type()
|
|
||||||
*
|
|
||||||
* @return Returns true if this is a multipart mime, and therefore
|
|
||||||
* getting subparts will succeed.
|
|
||||||
*/
|
|
||||||
bool isMultipart() const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Get the number of atachments.
|
|
||||||
*
|
|
||||||
* @return Returns the number of sub-parts for this.
|
|
||||||
*/
|
|
||||||
S32 subPartCount() const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Get the indicated attachment.
|
|
||||||
*
|
|
||||||
* @param index Value from 0 to (subPartCount() - 1).
|
|
||||||
* @return Returns the indicated sub-part, or an invalid mime
|
|
||||||
* index on failure.
|
|
||||||
*/
|
|
||||||
LLMimeIndex subPart(S32 index) const;
|
|
||||||
//@}
|
|
||||||
|
|
||||||
/* @name Interface for building, testing, and helpers for typical use.
|
|
||||||
*/
|
|
||||||
//@{
|
|
||||||
/**
|
|
||||||
* @brief Default constructor - creates a useless LLMimeIndex.
|
|
||||||
*/
|
|
||||||
LLMimeIndex();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Full constructor.
|
|
||||||
*
|
|
||||||
* @param headers The complete headers.
|
|
||||||
* @param content_offset The number of bytes to the start of the
|
|
||||||
* data segment of this mime entity from the start of the stream
|
|
||||||
* or buffer.
|
|
||||||
*/
|
|
||||||
LLMimeIndex(LLSD headers, S32 content_offset);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Copy constructor.
|
|
||||||
*
|
|
||||||
* @param mime The other mime object.
|
|
||||||
*/
|
|
||||||
LLMimeIndex(const LLMimeIndex& mime);
|
|
||||||
|
|
||||||
// @brief Destructor.
|
|
||||||
~LLMimeIndex();
|
|
||||||
|
|
||||||
/*
|
|
||||||
* @breif Assignment operator.
|
|
||||||
*
|
|
||||||
* @param mime The other mime object.
|
|
||||||
* @return Returns this after assignment.
|
|
||||||
*/
|
|
||||||
LLMimeIndex& operator=(const LLMimeIndex& mime);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Add attachment information as a sub-part to a multipart mime.
|
|
||||||
*
|
|
||||||
* @param sub_part the part to attach.
|
|
||||||
* @return Returns true on success, false on failure.
|
|
||||||
*/
|
|
||||||
bool attachSubPart(LLMimeIndex sub_part);
|
|
||||||
//@}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
// Implementation.
|
|
||||||
class Impl;
|
|
||||||
Impl* mImpl;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @class LLMimeParser
|
|
||||||
* @brief This class implements a MIME parser and verifier.
|
|
||||||
*
|
|
||||||
* THOROUGH_DESCRIPTION
|
|
||||||
*/
|
|
||||||
class LLMimeParser
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
// @brief Make a new mime parser.
|
|
||||||
LLMimeParser();
|
|
||||||
|
|
||||||
// @brief Mime parser Destructor.
|
|
||||||
~LLMimeParser();
|
|
||||||
|
|
||||||
// @brief Reset internal state of this parser.
|
|
||||||
void reset();
|
|
||||||
|
|
||||||
|
|
||||||
/* @name Index generation interface.
|
|
||||||
*/
|
|
||||||
//@{
|
|
||||||
/**
|
|
||||||
* @brief Parse a stream to find the mime index information.
|
|
||||||
*
|
|
||||||
* This method will scan the istr until a single complete mime
|
|
||||||
* entity is read or EOF. The istr will be modified by this
|
|
||||||
* parsing, so pass in a temporary stream or rewind/reset the
|
|
||||||
* stream after this call.
|
|
||||||
* @param istr An istream which contains a mime entity.
|
|
||||||
* @param index[out] The parsed output.
|
|
||||||
* @return Returns true if an index was parsed and no errors occurred.
|
|
||||||
*/
|
|
||||||
bool parseIndex(std::istream& istr, LLMimeIndex& index);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Parse a vector to find the mime index information.
|
|
||||||
*
|
|
||||||
* @param buffer A vector with data to parse.
|
|
||||||
* @param index[out] The parsed output.
|
|
||||||
* @return Returns true if an index was parsed and no errors occurred.
|
|
||||||
*/
|
|
||||||
bool parseIndex(const std::vector<U8>& buffer, LLMimeIndex& index);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Parse a stream to find the mime index information.
|
|
||||||
*
|
|
||||||
* This method will scan the istr until a single complete mime
|
|
||||||
* entity is read, an EOF, or limit bytes have been scanned. The
|
|
||||||
* istr will be modified by this parsing, so pass in a temporary
|
|
||||||
* stream or rewind/reset the stream after this call.
|
|
||||||
* @param istr An istream which contains a mime entity.
|
|
||||||
* @param limit The maximum number of bytes to scan.
|
|
||||||
* @param index[out] The parsed output.
|
|
||||||
* @return Returns true if an index was parsed and no errors occurred.
|
|
||||||
*/
|
|
||||||
bool parseIndex(std::istream& istr, S32 limit, LLMimeIndex& index);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Parse a memory bufffer to find the mime index information.
|
|
||||||
*
|
|
||||||
* @param buffer The start of the buffer to parse.
|
|
||||||
* @param buffer_length The length of the buffer.
|
|
||||||
* @param index[out] The parsed output.
|
|
||||||
* @return Returns true if an index was parsed and no errors occurred.
|
|
||||||
*/
|
|
||||||
bool parseIndex(const U8* buffer, S32 buffer_length, LLMimeIndex& index);
|
|
||||||
//@}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
//bool verify(std::istream& istr, LLMimeIndex& index) const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
//bool verify(U8* buffer, S32 buffer_length, LLMimeIndex& index) const;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
// Implementation.
|
|
||||||
class Impl;
|
|
||||||
Impl& mImpl;
|
|
||||||
|
|
||||||
private:
|
|
||||||
// @brief Not implemneted to prevent copy consturction.
|
|
||||||
LLMimeParser(const LLMimeParser& parser);
|
|
||||||
|
|
||||||
// @brief Not implemneted to prevent assignment.
|
|
||||||
LLMimeParser& operator=(const LLMimeParser& mime);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // LL_LLMIME_H
|
|
||||||
@@ -1,445 +0,0 @@
|
|||||||
/**
|
|
||||||
* @file llmime_test.cpp
|
|
||||||
* @author Phoenix
|
|
||||||
* @date 2006-12-24
|
|
||||||
* @brief BRIEF_DESC of llmime_test.cpp
|
|
||||||
*
|
|
||||||
* $LicenseInfo:firstyear=2006&license=viewerlgpl$
|
|
||||||
* Second Life Viewer Source Code
|
|
||||||
* Copyright (C) 2010, Linden Research, Inc.
|
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
|
||||||
* License as published by the Free Software Foundation;
|
|
||||||
* version 2.1 of the License only.
|
|
||||||
*
|
|
||||||
* This library is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
* Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with this library; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*
|
|
||||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
|
||||||
* $/LicenseInfo$
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "linden_common.h"
|
|
||||||
|
|
||||||
#include "llsdserialize.h"
|
|
||||||
|
|
||||||
#include "../llmime.h"
|
|
||||||
|
|
||||||
#include "../test/lltut.h"
|
|
||||||
|
|
||||||
namespace tut
|
|
||||||
{
|
|
||||||
struct mime_index
|
|
||||||
{
|
|
||||||
};
|
|
||||||
typedef test_group<mime_index> mime_index_t;
|
|
||||||
typedef mime_index_t::object mime_index_object_t;
|
|
||||||
tut::mime_index_t tut_mime_index("LLMime");
|
|
||||||
|
|
||||||
template<> template<>
|
|
||||||
void mime_index_object_t::test<1>()
|
|
||||||
{
|
|
||||||
LLMimeIndex mime;
|
|
||||||
ensure("no headers", mime.headers().isUndefined());
|
|
||||||
ensure_equals("invalid offset", mime.offset(), -1);
|
|
||||||
ensure_equals("invalid content length", mime.contentLength(), -1);
|
|
||||||
ensure("no content type", mime.contentType().empty());
|
|
||||||
ensure("not multipart", !mime.isMultipart());
|
|
||||||
ensure_equals("no attachments", mime.subPartCount(), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<> template<>
|
|
||||||
void mime_index_object_t::test<2>()
|
|
||||||
{
|
|
||||||
const S32 CONTENT_LENGTH = 6000;
|
|
||||||
const S32 CONTENT_OFFSET = 100;
|
|
||||||
const std::string CONTENT_TYPE = std::string("image/j2c");
|
|
||||||
LLSD headers;
|
|
||||||
headers["Content-Length"] = CONTENT_LENGTH;
|
|
||||||
headers["Content-Type"] = CONTENT_TYPE;
|
|
||||||
LLMimeIndex mime(headers, CONTENT_OFFSET);
|
|
||||||
ensure("headers are map", mime.headers().isMap());
|
|
||||||
ensure_equals("offset", mime.offset(), CONTENT_OFFSET);
|
|
||||||
ensure_equals("content length", mime.contentLength(), CONTENT_LENGTH);
|
|
||||||
ensure_equals("type is image/j2c", mime.contentType(), CONTENT_TYPE);
|
|
||||||
ensure("not multipart", !mime.isMultipart());
|
|
||||||
ensure_equals("no attachments", mime.subPartCount(), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<> template<>
|
|
||||||
void mime_index_object_t::test<3>()
|
|
||||||
{
|
|
||||||
const S32 MULTI_CONTENT_LENGTH = 8000;
|
|
||||||
const S32 MULTI_CONTENT_OFFSET = 100;
|
|
||||||
const std::string MULTI_CONTENT_TYPE = std::string("multipart/mixed");
|
|
||||||
LLSD headers;
|
|
||||||
headers["Content-Length"] = MULTI_CONTENT_LENGTH;
|
|
||||||
headers["Content-Type"] = MULTI_CONTENT_TYPE;
|
|
||||||
LLMimeIndex mime(headers, MULTI_CONTENT_OFFSET);
|
|
||||||
LL_INFOS() << "headers: " << LLSDOStreamer<LLSDNotationFormatter>(headers)
|
|
||||||
<< LL_ENDL;
|
|
||||||
|
|
||||||
|
|
||||||
const S32 META_CONTENT_LENGTH = 700;
|
|
||||||
const S32 META_CONTENT_OFFSET = 69;
|
|
||||||
const std::string META_CONTENT_TYPE = std::string(
|
|
||||||
"text/llsd+xml");
|
|
||||||
headers = LLSD::emptyMap();
|
|
||||||
headers["Content-Length"] = META_CONTENT_LENGTH;
|
|
||||||
headers["Content-Type"] = META_CONTENT_TYPE;
|
|
||||||
LLMimeIndex meta(headers, META_CONTENT_OFFSET);
|
|
||||||
mime.attachSubPart(meta);
|
|
||||||
|
|
||||||
const S32 IMAGE_CONTENT_LENGTH = 6000;
|
|
||||||
const S32 IMAGE_CONTENT_OFFSET = 200;
|
|
||||||
const std::string IMAGE_CONTENT_TYPE = std::string("image/j2c");
|
|
||||||
headers = LLSD::emptyMap();
|
|
||||||
headers["Content-Length"] = IMAGE_CONTENT_LENGTH;
|
|
||||||
headers["Content-Type"] = IMAGE_CONTENT_TYPE;
|
|
||||||
LLMimeIndex image(headers, IMAGE_CONTENT_OFFSET);
|
|
||||||
mime.attachSubPart(image);
|
|
||||||
|
|
||||||
// make sure we have a valid multi-part
|
|
||||||
ensure("is multipart", mime.isMultipart());
|
|
||||||
ensure_equals("multi offset", mime.offset(), MULTI_CONTENT_OFFSET);
|
|
||||||
ensure_equals(
|
|
||||||
"multi content length",
|
|
||||||
mime.contentLength(),
|
|
||||||
MULTI_CONTENT_LENGTH);
|
|
||||||
ensure_equals("two attachments", mime.subPartCount(), 2);
|
|
||||||
|
|
||||||
// make sure ranged gets do the right thing with out of bounds
|
|
||||||
// sub-parts.
|
|
||||||
LLMimeIndex invalid_child(mime.subPart(-1));
|
|
||||||
ensure("no headers", invalid_child.headers().isUndefined());
|
|
||||||
ensure_equals("invalid offset", invalid_child.offset(), -1);
|
|
||||||
ensure_equals(
|
|
||||||
"invalid content length", invalid_child.contentLength(), -1);
|
|
||||||
ensure("no content type", invalid_child.contentType().empty());
|
|
||||||
ensure("not multipart", !invalid_child.isMultipart());
|
|
||||||
ensure_equals("no attachments", invalid_child.subPartCount(), 0);
|
|
||||||
|
|
||||||
invalid_child = mime.subPart(2);
|
|
||||||
ensure("no headers", invalid_child.headers().isUndefined());
|
|
||||||
ensure_equals("invalid offset", invalid_child.offset(), -1);
|
|
||||||
ensure_equals(
|
|
||||||
"invalid content length", invalid_child.contentLength(), -1);
|
|
||||||
ensure("no content type", invalid_child.contentType().empty());
|
|
||||||
ensure("not multipart", !invalid_child.isMultipart());
|
|
||||||
ensure_equals("no attachments", invalid_child.subPartCount(), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<> template<>
|
|
||||||
void mime_index_object_t::test<4>()
|
|
||||||
{
|
|
||||||
const S32 MULTI_CONTENT_LENGTH = 8000;
|
|
||||||
const S32 MULTI_CONTENT_OFFSET = 100;
|
|
||||||
const std::string MULTI_CONTENT_TYPE = std::string("multipart/mixed");
|
|
||||||
LLSD headers;
|
|
||||||
headers["Content-Length"] = MULTI_CONTENT_LENGTH;
|
|
||||||
headers["Content-Type"] = MULTI_CONTENT_TYPE;
|
|
||||||
LLMimeIndex mime(headers, MULTI_CONTENT_OFFSET);
|
|
||||||
|
|
||||||
const S32 META_CONTENT_LENGTH = 700;
|
|
||||||
const S32 META_CONTENT_OFFSET = 69;
|
|
||||||
const std::string META_CONTENT_TYPE = std::string(
|
|
||||||
"application/llsd+xml");
|
|
||||||
headers = LLSD::emptyMap();
|
|
||||||
headers["Content-Length"] = META_CONTENT_LENGTH;
|
|
||||||
headers["Content-Type"] = META_CONTENT_TYPE;
|
|
||||||
LLMimeIndex meta(headers, META_CONTENT_OFFSET);
|
|
||||||
mime.attachSubPart(meta);
|
|
||||||
|
|
||||||
const S32 IMAGE_CONTENT_LENGTH = 6000;
|
|
||||||
const S32 IMAGE_CONTENT_OFFSET = 200;
|
|
||||||
const std::string IMAGE_CONTENT_TYPE = std::string("image/j2c");
|
|
||||||
headers = LLSD::emptyMap();
|
|
||||||
headers["Content-Length"] = IMAGE_CONTENT_LENGTH;
|
|
||||||
headers["Content-Type"] = IMAGE_CONTENT_TYPE;
|
|
||||||
LLMimeIndex image(headers, IMAGE_CONTENT_OFFSET);
|
|
||||||
mime.attachSubPart(image);
|
|
||||||
|
|
||||||
// check what we have
|
|
||||||
ensure("is multipart", mime.isMultipart());
|
|
||||||
ensure_equals("multi offset", mime.offset(), MULTI_CONTENT_OFFSET);
|
|
||||||
ensure_equals(
|
|
||||||
"multi content length",
|
|
||||||
mime.contentLength(),
|
|
||||||
MULTI_CONTENT_LENGTH);
|
|
||||||
ensure_equals("two attachments", mime.subPartCount(), 2);
|
|
||||||
|
|
||||||
LLMimeIndex actual_meta = mime.subPart(0);
|
|
||||||
ensure_equals(
|
|
||||||
"meta type", actual_meta.contentType(), META_CONTENT_TYPE);
|
|
||||||
ensure_equals(
|
|
||||||
"meta offset", actual_meta.offset(), META_CONTENT_OFFSET);
|
|
||||||
ensure_equals(
|
|
||||||
"meta content length",
|
|
||||||
actual_meta.contentLength(),
|
|
||||||
META_CONTENT_LENGTH);
|
|
||||||
|
|
||||||
LLMimeIndex actual_image = mime.subPart(1);
|
|
||||||
ensure_equals(
|
|
||||||
"image type", actual_image.contentType(), IMAGE_CONTENT_TYPE);
|
|
||||||
ensure_equals(
|
|
||||||
"image offset", actual_image.offset(), IMAGE_CONTENT_OFFSET);
|
|
||||||
ensure_equals(
|
|
||||||
"image content length",
|
|
||||||
actual_image.contentLength(),
|
|
||||||
IMAGE_CONTENT_LENGTH);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
template<> template<>
|
|
||||||
void mime_index_object_t::test<5>()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
template<> template<>
|
|
||||||
void mime_index_object_t::test<6>()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
template<> template<>
|
|
||||||
void mime_index_object_t::test<7>()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
template<> template<>
|
|
||||||
void mime_index_object_t::test<8>()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
template<> template<>
|
|
||||||
void mime_index_object_t::test<>()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
namespace tut
|
|
||||||
{
|
|
||||||
struct mime_parse
|
|
||||||
{
|
|
||||||
};
|
|
||||||
typedef test_group<mime_parse> mime_parse_t;
|
|
||||||
typedef mime_parse_t::object mime_parse_object_t;
|
|
||||||
tut::mime_parse_t tut_mime_parse("LLMimeParse");
|
|
||||||
|
|
||||||
template<> template<>
|
|
||||||
void mime_parse_object_t::test<1>()
|
|
||||||
{
|
|
||||||
// parse one mime object
|
|
||||||
const std::string SERIALIZED_MIME("Content-Length: 200\r\nContent-Type: text/plain\r\n\r\naaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbcccccccccc\r\n");
|
|
||||||
std::stringstream istr;
|
|
||||||
istr.str(SERIALIZED_MIME);
|
|
||||||
LLMimeIndex mime;
|
|
||||||
LLMimeParser parser;
|
|
||||||
bool ok = parser.parseIndex(istr, mime);
|
|
||||||
ensure("Parse successful.", ok);
|
|
||||||
ensure_equals("content type", mime.contentType(), "text/plain");
|
|
||||||
ensure_equals("content length", mime.contentLength(), 200);
|
|
||||||
ensure_equals("offset", mime.offset(), 49);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<> template<>
|
|
||||||
void mime_parse_object_t::test<2>()
|
|
||||||
{
|
|
||||||
// make sure we only parse one.
|
|
||||||
const std::string SERIALIZED_MIME("Content-Length: 200\r\nContent-Type: text/plain\r\n\r\naaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbcccccccccc\r\n\r\nContent-Length: 200\r\nContent-Type: text/plain\r\n\r\naaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbcccccccccc\r\n\r\n");
|
|
||||||
std::stringstream istr;
|
|
||||||
istr.str(SERIALIZED_MIME);
|
|
||||||
LLMimeIndex mime;
|
|
||||||
LLMimeParser parser;
|
|
||||||
bool ok = parser.parseIndex(istr, mime);
|
|
||||||
ensure("Parse successful.", ok);
|
|
||||||
ensure("not multipart.", !mime.isMultipart());
|
|
||||||
ensure_equals("content type", mime.contentType(), "text/plain");
|
|
||||||
ensure_equals("content length", mime.contentLength(), 200);
|
|
||||||
ensure_equals("offset", mime.offset(), 49);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<> template<>
|
|
||||||
void mime_parse_object_t::test<3>()
|
|
||||||
{
|
|
||||||
// test multi-part and lack of content length for some of it.
|
|
||||||
/*
|
|
||||||
Content-Type: multipart/mixed; boundary="segment"rnContent-Length: 148rnrn--segmentrnContent-Type: text/plainrnrnsome datarnrn--segmentrnContent-Type: text/xml; charset=UTF-8rnContent-Length: 22rnrn<llsd><undef /></llsd>rnrn
|
|
||||||
*/
|
|
||||||
const std::string SERIALIZED_MIME("Content-Type: multipart/mixed; boundary=\"segment\"\r\nContent-Length: 150\r\n\r\n--segment\r\nContent-Type: text/plain\r\n\r\nsome data\r\n\r\n--segment\r\nContent-Type: text/xml; charset=UTF-8\r\nContent-Length: 22\r\n\r\n<llsd><undef /></llsd>\r\n\r\n");
|
|
||||||
std::stringstream istr;
|
|
||||||
istr.str(SERIALIZED_MIME);
|
|
||||||
LLMimeIndex mime;
|
|
||||||
LLMimeParser parser;
|
|
||||||
bool ok = parser.parseIndex(istr, mime);
|
|
||||||
ensure("Parse successful.", ok);
|
|
||||||
ensure("is multipart.", mime.isMultipart());
|
|
||||||
ensure_equals("sub-part count", mime.subPartCount(), 2);
|
|
||||||
ensure_equals("content length", mime.contentLength(), 150);
|
|
||||||
ensure_equals("data offset for multipart", mime.offset(), 74);
|
|
||||||
|
|
||||||
LLMimeIndex mime_plain(mime.subPart(0));
|
|
||||||
ensure_equals(
|
|
||||||
"first part type",
|
|
||||||
mime_plain.contentType(),
|
|
||||||
"text/plain");
|
|
||||||
ensure_equals(
|
|
||||||
"first part content length not known.",
|
|
||||||
mime_plain.contentLength(),
|
|
||||||
-1);
|
|
||||||
ensure_equals("first part offset", mime_plain.offset(), 113);
|
|
||||||
|
|
||||||
LLMimeIndex mime_xml(mime.subPart(1));
|
|
||||||
ensure_equals(
|
|
||||||
"second part type",
|
|
||||||
mime_xml.contentType(),
|
|
||||||
"text/xml; charset=UTF-8");
|
|
||||||
ensure_equals(
|
|
||||||
"second part content length",
|
|
||||||
mime_xml.contentLength(),
|
|
||||||
22);
|
|
||||||
ensure_equals("second part offset", mime_xml.offset(), 198);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<> template<>
|
|
||||||
void mime_parse_object_t::test<4>()
|
|
||||||
{
|
|
||||||
// test multi-part, unquoted separator, and premature eof conditions
|
|
||||||
/*
|
|
||||||
Content-Type: multipart/mixed; boundary=segmentrnContent-Length: 220rnrn--segmentrnContent-Type: text/plainrnContent-Length: 55rnrnhow are you today?rnI do not know. I guess I am:n'fine'rnrn--segmentrnContent-Type: text/xml; charset=UTF-8rnContent-Length: 22rnrn<llsd><undef /></llsd>rnrn */
|
|
||||||
const std::string SERIALIZED_MIME("Content-Type: multipart/mixed; boundary=segment\r\nContent-Length: 220\r\n\r\n--segment\r\nContent-Type: text/plain\r\nContent-Length: 55\r\n\r\nhow are you today?\r\nI do not know. I guess I am:\n'fine'\r\n\r\n--segment\r\nContent-Type: text/xml; charset=UTF-8\r\nContent-Length: 22\r\n\r\n<llsd><undef /></llsd>\r\n\r\n");
|
|
||||||
std::stringstream istr;
|
|
||||||
istr.str(SERIALIZED_MIME);
|
|
||||||
LLMimeIndex mime;
|
|
||||||
LLMimeParser parser;
|
|
||||||
bool ok = parser.parseIndex(istr, mime);
|
|
||||||
ensure("Parse successful.", ok);
|
|
||||||
ensure("is multipart.", mime.isMultipart());
|
|
||||||
ensure_equals("sub-part count", mime.subPartCount(), 2);
|
|
||||||
ensure_equals("content length", mime.contentLength(), 220);
|
|
||||||
ensure_equals("data offset for multipart", mime.offset(), 72);
|
|
||||||
|
|
||||||
LLMimeIndex mime_plain(mime.subPart(0));
|
|
||||||
ensure_equals(
|
|
||||||
"first part type",
|
|
||||||
mime_plain.contentType(),
|
|
||||||
"text/plain");
|
|
||||||
ensure_equals(
|
|
||||||
"first part content length",
|
|
||||||
mime_plain.contentLength(),
|
|
||||||
55);
|
|
||||||
ensure_equals("first part offset", mime_plain.offset(), 131);
|
|
||||||
|
|
||||||
LLMimeIndex mime_xml(mime.subPart(1));
|
|
||||||
ensure_equals(
|
|
||||||
"second part type",
|
|
||||||
mime_xml.contentType(),
|
|
||||||
"text/xml; charset=UTF-8");
|
|
||||||
ensure_equals(
|
|
||||||
"second part content length",
|
|
||||||
mime_xml.contentLength(),
|
|
||||||
22);
|
|
||||||
ensure_equals("second part offset", mime_xml.offset(), 262);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<> template<>
|
|
||||||
void mime_parse_object_t::test<5>()
|
|
||||||
{
|
|
||||||
// test multi-part with multiple params
|
|
||||||
const std::string SERIALIZED_MIME("Content-Type: multipart/mixed; boundary=segment; comment=\"testing multiple params.\"\r\nContent-Length: 220\r\n\r\n--segment\r\nContent-Type: text/plain\r\nContent-Length: 55\r\n\r\nhow are you today?\r\nI do not know. I guess I am:\n'fine'\r\n\r\n--segment\r\nContent-Type: text/xml; charset=UTF-8\r\nContent-Length: 22\r\n\r\n<llsd><undef /></llsd>\r\n\r\n");
|
|
||||||
std::stringstream istr;
|
|
||||||
istr.str(SERIALIZED_MIME);
|
|
||||||
LLMimeIndex mime;
|
|
||||||
LLMimeParser parser;
|
|
||||||
bool ok = parser.parseIndex(istr, mime);
|
|
||||||
ensure("Parse successful.", ok);
|
|
||||||
ensure("is multipart.", mime.isMultipart());
|
|
||||||
ensure_equals("sub-part count", mime.subPartCount(), 2);
|
|
||||||
ensure_equals("content length", mime.contentLength(), 220);
|
|
||||||
|
|
||||||
LLMimeIndex mime_plain(mime.subPart(0));
|
|
||||||
ensure_equals(
|
|
||||||
"first part type",
|
|
||||||
mime_plain.contentType(),
|
|
||||||
"text/plain");
|
|
||||||
ensure_equals(
|
|
||||||
"first part content length",
|
|
||||||
mime_plain.contentLength(),
|
|
||||||
55);
|
|
||||||
|
|
||||||
LLMimeIndex mime_xml(mime.subPart(1));
|
|
||||||
ensure_equals(
|
|
||||||
"second part type",
|
|
||||||
mime_xml.contentType(),
|
|
||||||
"text/xml; charset=UTF-8");
|
|
||||||
ensure_equals(
|
|
||||||
"second part content length",
|
|
||||||
mime_xml.contentLength(),
|
|
||||||
22);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<> template<>
|
|
||||||
void mime_parse_object_t::test<6>()
|
|
||||||
{
|
|
||||||
// test multi-part with no specified boundary and eof
|
|
||||||
/*
|
|
||||||
Content-Type: multipart/relatedrnContent-Length: 220rnrn--rnContent-Type: text/plainrnContent-Length: 55rnrnhow are you today?rnI do not know. I guess I am:n'fine'rnrn--rnContent-Type: text/xml; charset=UTF-8rnContent-Length: 22rnrn<llsd><undef /></llsd>rnrn
|
|
||||||
*/
|
|
||||||
const std::string SERIALIZED_MIME("Content-Type: multipart/related\r\nContent-Length: 500\r\n\r\n--\r\nContent-Type: text/plain\r\nContent-Length: 55\r\n\r\nhow are you today?\r\nI do not know. I guess I am:\n'fine'\r\n\r\n--\r\nContent-Type: text/xml; charset=UTF-8\r\nContent-Length: 22\r\n\r\n<llsd><undef /></llsd>\r\n\r\n");
|
|
||||||
std::stringstream istr;
|
|
||||||
istr.str(SERIALIZED_MIME);
|
|
||||||
LLMimeIndex mime;
|
|
||||||
LLMimeParser parser;
|
|
||||||
bool ok = parser.parseIndex(istr, mime);
|
|
||||||
ensure("Parse successful.", ok);
|
|
||||||
ensure("is multipart.", mime.isMultipart());
|
|
||||||
ensure_equals("sub-part count", mime.subPartCount(), 2);
|
|
||||||
ensure_equals("content length", mime.contentLength(), 500);
|
|
||||||
ensure_equals("data offset for multipart", mime.offset(), 56);
|
|
||||||
|
|
||||||
LLMimeIndex mime_plain(mime.subPart(0));
|
|
||||||
ensure_equals(
|
|
||||||
"first part type",
|
|
||||||
mime_plain.contentType(),
|
|
||||||
"text/plain");
|
|
||||||
ensure_equals(
|
|
||||||
"first part content length",
|
|
||||||
mime_plain.contentLength(),
|
|
||||||
55);
|
|
||||||
ensure_equals("first part offset", mime_plain.offset(), 108);
|
|
||||||
|
|
||||||
LLMimeIndex mime_xml(mime.subPart(1));
|
|
||||||
ensure_equals(
|
|
||||||
"second part type",
|
|
||||||
mime_xml.contentType(),
|
|
||||||
"text/xml; charset=UTF-8");
|
|
||||||
ensure_equals(
|
|
||||||
"second part content length",
|
|
||||||
mime_xml.contentLength(),
|
|
||||||
22);
|
|
||||||
ensure_equals("second part offset", mime_xml.offset(), 232);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
template<> template<>
|
|
||||||
void mime_parse_object_t::test<>()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
template<> template<>
|
|
||||||
void mime_parse_object_t::test<>()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
template<> template<>
|
|
||||||
void mime_parse_object_t::test<>()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
template<> template<>
|
|
||||||
void mime_parse_object_t::test<>()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
@@ -34,9 +34,6 @@
|
|||||||
#ifndef LLMIMETYPES_H
|
#ifndef LLMIMETYPES_H
|
||||||
#define LLMIMETYPES_H
|
#define LLMIMETYPES_H
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <map>
|
|
||||||
|
|
||||||
class LLMIMETypes
|
class LLMIMETypes
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -41,7 +41,6 @@ set(test_SOURCE_FILES
|
|||||||
llinventoryparcel_tut.cpp
|
llinventoryparcel_tut.cpp
|
||||||
lliohttpserver_tut.cpp
|
lliohttpserver_tut.cpp
|
||||||
lljoint_tut.cpp
|
lljoint_tut.cpp
|
||||||
llmime_tut.cpp
|
|
||||||
llmessageconfig_tut.cpp
|
llmessageconfig_tut.cpp
|
||||||
llmodularmath_tut.cpp
|
llmodularmath_tut.cpp
|
||||||
llnamevalue_tut.cpp
|
llnamevalue_tut.cpp
|
||||||
|
|||||||
@@ -1,448 +0,0 @@
|
|||||||
/**
|
|
||||||
* @file llmime_tut.cpp
|
|
||||||
* @author Phoenix
|
|
||||||
* @date 2006-12-24
|
|
||||||
* @brief BRIEF_DESC of llmime_tut.cpp
|
|
||||||
*
|
|
||||||
* $LicenseInfo:firstyear=2006&license=viewergpl$
|
|
||||||
*
|
|
||||||
* Copyright (c) 2006-2009, Linden Research, Inc.
|
|
||||||
*
|
|
||||||
* Second Life Viewer Source Code
|
|
||||||
* The source code in this file ("Source Code") is provided by Linden Lab
|
|
||||||
* to you under the terms of the GNU General Public License, version 2.0
|
|
||||||
* ("GPL"), unless you have obtained a separate licensing agreement
|
|
||||||
* ("Other License"), formally executed by you and Linden Lab. Terms of
|
|
||||||
* the GPL can be found in doc/GPL-license.txt in this distribution, or
|
|
||||||
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
|
|
||||||
*
|
|
||||||
* There are special exceptions to the terms and conditions of the GPL as
|
|
||||||
* it is applied to this Source Code. View the full text of the exception
|
|
||||||
* in the file doc/FLOSS-exception.txt in this software distribution, or
|
|
||||||
* online at
|
|
||||||
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
|
|
||||||
*
|
|
||||||
* By copying, modifying or distributing this software, you acknowledge
|
|
||||||
* that you have read and understood your obligations described above,
|
|
||||||
* and agree to abide by those obligations.
|
|
||||||
*
|
|
||||||
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
|
|
||||||
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
|
|
||||||
* COMPLETENESS OR PERFORMANCE.
|
|
||||||
* $/LicenseInfo$
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <tut/tut.hpp>
|
|
||||||
#include "linden_common.h"
|
|
||||||
#include "llmime.h"
|
|
||||||
#include "llsdserialize.h"
|
|
||||||
|
|
||||||
namespace tut
|
|
||||||
{
|
|
||||||
struct mime_index
|
|
||||||
{
|
|
||||||
};
|
|
||||||
typedef test_group<mime_index> mime_index_t;
|
|
||||||
typedef mime_index_t::object mime_index_object_t;
|
|
||||||
tut::mime_index_t tut_mime_index("mime_index");
|
|
||||||
|
|
||||||
template<> template<>
|
|
||||||
void mime_index_object_t::test<1>()
|
|
||||||
{
|
|
||||||
LLMimeIndex mime;
|
|
||||||
ensure("no headers", mime.headers().isUndefined());
|
|
||||||
ensure_equals("invalid offset", mime.offset(), -1);
|
|
||||||
ensure_equals("invalid content length", mime.contentLength(), -1);
|
|
||||||
ensure("no content type", mime.contentType().empty());
|
|
||||||
ensure("not multipart", !mime.isMultipart());
|
|
||||||
ensure_equals("no attachments", mime.subPartCount(), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<> template<>
|
|
||||||
void mime_index_object_t::test<2>()
|
|
||||||
{
|
|
||||||
const S32 CONTENT_LENGTH = 6000;
|
|
||||||
const S32 CONTENT_OFFSET = 100;
|
|
||||||
const std::string CONTENT_TYPE = std::string("image/j2c");
|
|
||||||
LLSD headers;
|
|
||||||
headers["Content-Length"] = CONTENT_LENGTH;
|
|
||||||
headers["Content-Type"] = CONTENT_TYPE;
|
|
||||||
LLMimeIndex mime(headers, CONTENT_OFFSET);
|
|
||||||
ensure("headers are map", mime.headers().isMap());
|
|
||||||
ensure_equals("offset", mime.offset(), CONTENT_OFFSET);
|
|
||||||
ensure_equals("content length", mime.contentLength(), CONTENT_LENGTH);
|
|
||||||
ensure_equals("type is image/j2c", mime.contentType(), CONTENT_TYPE);
|
|
||||||
ensure("not multipart", !mime.isMultipart());
|
|
||||||
ensure_equals("no attachments", mime.subPartCount(), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<> template<>
|
|
||||||
void mime_index_object_t::test<3>()
|
|
||||||
{
|
|
||||||
const S32 MULTI_CONTENT_LENGTH = 8000;
|
|
||||||
const S32 MULTI_CONTENT_OFFSET = 100;
|
|
||||||
const std::string MULTI_CONTENT_TYPE = std::string("multipart/mixed");
|
|
||||||
LLSD headers;
|
|
||||||
headers["Content-Length"] = MULTI_CONTENT_LENGTH;
|
|
||||||
headers["Content-Type"] = MULTI_CONTENT_TYPE;
|
|
||||||
LLMimeIndex mime(headers, MULTI_CONTENT_OFFSET);
|
|
||||||
LL_INFOS() << "headers: " << LLSDOStreamer<LLSDNotationFormatter>(headers)
|
|
||||||
<< LL_ENDL;
|
|
||||||
|
|
||||||
|
|
||||||
const S32 META_CONTENT_LENGTH = 700;
|
|
||||||
const S32 META_CONTENT_OFFSET = 69;
|
|
||||||
const std::string META_CONTENT_TYPE = std::string(
|
|
||||||
"text/llsd+xml");
|
|
||||||
headers = LLSD::emptyMap();
|
|
||||||
headers["Content-Length"] = META_CONTENT_LENGTH;
|
|
||||||
headers["Content-Type"] = META_CONTENT_TYPE;
|
|
||||||
LLMimeIndex meta(headers, META_CONTENT_OFFSET);
|
|
||||||
mime.attachSubPart(meta);
|
|
||||||
|
|
||||||
const S32 IMAGE_CONTENT_LENGTH = 6000;
|
|
||||||
const S32 IMAGE_CONTENT_OFFSET = 200;
|
|
||||||
const std::string IMAGE_CONTENT_TYPE = std::string("image/j2c");
|
|
||||||
headers = LLSD::emptyMap();
|
|
||||||
headers["Content-Length"] = IMAGE_CONTENT_LENGTH;
|
|
||||||
headers["Content-Type"] = IMAGE_CONTENT_TYPE;
|
|
||||||
LLMimeIndex image(headers, IMAGE_CONTENT_OFFSET);
|
|
||||||
mime.attachSubPart(image);
|
|
||||||
|
|
||||||
// make sure we have a valid multi-part
|
|
||||||
ensure("is multipart", mime.isMultipart());
|
|
||||||
ensure_equals("multi offset", mime.offset(), MULTI_CONTENT_OFFSET);
|
|
||||||
ensure_equals(
|
|
||||||
"multi content length",
|
|
||||||
mime.contentLength(),
|
|
||||||
MULTI_CONTENT_LENGTH);
|
|
||||||
ensure_equals("two attachments", mime.subPartCount(), 2);
|
|
||||||
|
|
||||||
// make sure ranged gets do the right thing with out of bounds
|
|
||||||
// sub-parts.
|
|
||||||
LLMimeIndex invalid_child(mime.subPart(-1));
|
|
||||||
ensure("no headers", invalid_child.headers().isUndefined());
|
|
||||||
ensure_equals("invalid offset", invalid_child.offset(), -1);
|
|
||||||
ensure_equals(
|
|
||||||
"invalid content length", invalid_child.contentLength(), -1);
|
|
||||||
ensure("no content type", invalid_child.contentType().empty());
|
|
||||||
ensure("not multipart", !invalid_child.isMultipart());
|
|
||||||
ensure_equals("no attachments", invalid_child.subPartCount(), 0);
|
|
||||||
|
|
||||||
invalid_child = mime.subPart(2);
|
|
||||||
ensure("no headers", invalid_child.headers().isUndefined());
|
|
||||||
ensure_equals("invalid offset", invalid_child.offset(), -1);
|
|
||||||
ensure_equals(
|
|
||||||
"invalid content length", invalid_child.contentLength(), -1);
|
|
||||||
ensure("no content type", invalid_child.contentType().empty());
|
|
||||||
ensure("not multipart", !invalid_child.isMultipart());
|
|
||||||
ensure_equals("no attachments", invalid_child.subPartCount(), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<> template<>
|
|
||||||
void mime_index_object_t::test<4>()
|
|
||||||
{
|
|
||||||
const S32 MULTI_CONTENT_LENGTH = 8000;
|
|
||||||
const S32 MULTI_CONTENT_OFFSET = 100;
|
|
||||||
const std::string MULTI_CONTENT_TYPE = std::string("multipart/mixed");
|
|
||||||
LLSD headers;
|
|
||||||
headers["Content-Length"] = MULTI_CONTENT_LENGTH;
|
|
||||||
headers["Content-Type"] = MULTI_CONTENT_TYPE;
|
|
||||||
LLMimeIndex mime(headers, MULTI_CONTENT_OFFSET);
|
|
||||||
|
|
||||||
const S32 META_CONTENT_LENGTH = 700;
|
|
||||||
const S32 META_CONTENT_OFFSET = 69;
|
|
||||||
const std::string META_CONTENT_TYPE = std::string(
|
|
||||||
"application/llsd+xml");
|
|
||||||
headers = LLSD::emptyMap();
|
|
||||||
headers["Content-Length"] = META_CONTENT_LENGTH;
|
|
||||||
headers["Content-Type"] = META_CONTENT_TYPE;
|
|
||||||
LLMimeIndex meta(headers, META_CONTENT_OFFSET);
|
|
||||||
mime.attachSubPart(meta);
|
|
||||||
|
|
||||||
const S32 IMAGE_CONTENT_LENGTH = 6000;
|
|
||||||
const S32 IMAGE_CONTENT_OFFSET = 200;
|
|
||||||
const std::string IMAGE_CONTENT_TYPE = std::string("image/j2c");
|
|
||||||
headers = LLSD::emptyMap();
|
|
||||||
headers["Content-Length"] = IMAGE_CONTENT_LENGTH;
|
|
||||||
headers["Content-Type"] = IMAGE_CONTENT_TYPE;
|
|
||||||
LLMimeIndex image(headers, IMAGE_CONTENT_OFFSET);
|
|
||||||
mime.attachSubPart(image);
|
|
||||||
|
|
||||||
// check what we have
|
|
||||||
ensure("is multipart", mime.isMultipart());
|
|
||||||
ensure_equals("multi offset", mime.offset(), MULTI_CONTENT_OFFSET);
|
|
||||||
ensure_equals(
|
|
||||||
"multi content length",
|
|
||||||
mime.contentLength(),
|
|
||||||
MULTI_CONTENT_LENGTH);
|
|
||||||
ensure_equals("two attachments", mime.subPartCount(), 2);
|
|
||||||
|
|
||||||
LLMimeIndex actual_meta = mime.subPart(0);
|
|
||||||
ensure_equals(
|
|
||||||
"meta type", actual_meta.contentType(), META_CONTENT_TYPE);
|
|
||||||
ensure_equals(
|
|
||||||
"meta offset", actual_meta.offset(), META_CONTENT_OFFSET);
|
|
||||||
ensure_equals(
|
|
||||||
"meta content length",
|
|
||||||
actual_meta.contentLength(),
|
|
||||||
META_CONTENT_LENGTH);
|
|
||||||
|
|
||||||
LLMimeIndex actual_image = mime.subPart(1);
|
|
||||||
ensure_equals(
|
|
||||||
"image type", actual_image.contentType(), IMAGE_CONTENT_TYPE);
|
|
||||||
ensure_equals(
|
|
||||||
"image offset", actual_image.offset(), IMAGE_CONTENT_OFFSET);
|
|
||||||
ensure_equals(
|
|
||||||
"image content length",
|
|
||||||
actual_image.contentLength(),
|
|
||||||
IMAGE_CONTENT_LENGTH);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
template<> template<>
|
|
||||||
void mime_index_object_t::test<5>()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
template<> template<>
|
|
||||||
void mime_index_object_t::test<6>()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
template<> template<>
|
|
||||||
void mime_index_object_t::test<7>()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
template<> template<>
|
|
||||||
void mime_index_object_t::test<8>()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
template<> template<>
|
|
||||||
void mime_index_object_t::test<>()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
namespace tut
|
|
||||||
{
|
|
||||||
struct mime_parse
|
|
||||||
{
|
|
||||||
};
|
|
||||||
typedef test_group<mime_parse> mime_parse_t;
|
|
||||||
typedef mime_parse_t::object mime_parse_object_t;
|
|
||||||
tut::mime_parse_t tut_mime_parse("mime_parse");
|
|
||||||
|
|
||||||
template<> template<>
|
|
||||||
void mime_parse_object_t::test<1>()
|
|
||||||
{
|
|
||||||
// parse one mime object
|
|
||||||
const std::string SERIALIZED_MIME("Content-Length: 200\r\nContent-Type: text/plain\r\n\r\naaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbcccccccccc\r\n");
|
|
||||||
std::stringstream istr;
|
|
||||||
istr.str(SERIALIZED_MIME);
|
|
||||||
LLMimeIndex mime;
|
|
||||||
LLMimeParser parser;
|
|
||||||
bool ok = parser.parseIndex(istr, mime);
|
|
||||||
ensure("Parse successful.", ok);
|
|
||||||
ensure_equals("content type", mime.contentType(), "text/plain");
|
|
||||||
ensure_equals("content length", mime.contentLength(), 200);
|
|
||||||
ensure_equals("offset", mime.offset(), 49);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<> template<>
|
|
||||||
void mime_parse_object_t::test<2>()
|
|
||||||
{
|
|
||||||
// make sure we only parse one.
|
|
||||||
const std::string SERIALIZED_MIME("Content-Length: 200\r\nContent-Type: text/plain\r\n\r\naaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbcccccccccc\r\n\r\nContent-Length: 200\r\nContent-Type: text/plain\r\n\r\naaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbcccccccccc\r\n\r\n");
|
|
||||||
std::stringstream istr;
|
|
||||||
istr.str(SERIALIZED_MIME);
|
|
||||||
LLMimeIndex mime;
|
|
||||||
LLMimeParser parser;
|
|
||||||
bool ok = parser.parseIndex(istr, mime);
|
|
||||||
ensure("Parse successful.", ok);
|
|
||||||
ensure("not multipart.", !mime.isMultipart());
|
|
||||||
ensure_equals("content type", mime.contentType(), "text/plain");
|
|
||||||
ensure_equals("content length", mime.contentLength(), 200);
|
|
||||||
ensure_equals("offset", mime.offset(), 49);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<> template<>
|
|
||||||
void mime_parse_object_t::test<3>()
|
|
||||||
{
|
|
||||||
// test multi-part and lack of content length for some of it.
|
|
||||||
/*
|
|
||||||
Content-Type: multipart/mixed; boundary="segment"rnContent-Length: 148rnrn--segmentrnContent-Type: text/plainrnrnsome datarnrn--segmentrnContent-Type: text/xml; charset=UTF-8rnContent-Length: 22rnrn<llsd><undef /></llsd>rnrn
|
|
||||||
*/
|
|
||||||
const std::string SERIALIZED_MIME("Content-Type: multipart/mixed; boundary=\"segment\"\r\nContent-Length: 150\r\n\r\n--segment\r\nContent-Type: text/plain\r\n\r\nsome data\r\n\r\n--segment\r\nContent-Type: text/xml; charset=UTF-8\r\nContent-Length: 22\r\n\r\n<llsd><undef /></llsd>\r\n\r\n");
|
|
||||||
std::stringstream istr;
|
|
||||||
istr.str(SERIALIZED_MIME);
|
|
||||||
LLMimeIndex mime;
|
|
||||||
LLMimeParser parser;
|
|
||||||
bool ok = parser.parseIndex(istr, mime);
|
|
||||||
ensure("Parse successful.", ok);
|
|
||||||
ensure("is multipart.", mime.isMultipart());
|
|
||||||
ensure_equals("sub-part count", mime.subPartCount(), 2);
|
|
||||||
ensure_equals("content length", mime.contentLength(), 150);
|
|
||||||
ensure_equals("data offset for multipart", mime.offset(), 74);
|
|
||||||
|
|
||||||
LLMimeIndex mime_plain(mime.subPart(0));
|
|
||||||
ensure_equals(
|
|
||||||
"first part type",
|
|
||||||
mime_plain.contentType(),
|
|
||||||
"text/plain");
|
|
||||||
ensure_equals(
|
|
||||||
"first part content length not known.",
|
|
||||||
mime_plain.contentLength(),
|
|
||||||
-1);
|
|
||||||
ensure_equals("first part offset", mime_plain.offset(), 113);
|
|
||||||
|
|
||||||
LLMimeIndex mime_xml(mime.subPart(1));
|
|
||||||
ensure_equals(
|
|
||||||
"second part type",
|
|
||||||
mime_xml.contentType(),
|
|
||||||
"text/xml; charset=UTF-8");
|
|
||||||
ensure_equals(
|
|
||||||
"second part content length",
|
|
||||||
mime_xml.contentLength(),
|
|
||||||
22);
|
|
||||||
ensure_equals("second part offset", mime_xml.offset(), 198);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<> template<>
|
|
||||||
void mime_parse_object_t::test<4>()
|
|
||||||
{
|
|
||||||
// test multi-part, unquoted separator, and premature eof conditions
|
|
||||||
/*
|
|
||||||
Content-Type: multipart/mixed; boundary=segmentrnContent-Length: 220rnrn--segmentrnContent-Type: text/plainrnContent-Length: 55rnrnhow are you today?rnI do not know. I guess I am:n'fine'rnrn--segmentrnContent-Type: text/xml; charset=UTF-8rnContent-Length: 22rnrn<llsd><undef /></llsd>rnrn */
|
|
||||||
const std::string SERIALIZED_MIME("Content-Type: multipart/mixed; boundary=segment\r\nContent-Length: 220\r\n\r\n--segment\r\nContent-Type: text/plain\r\nContent-Length: 55\r\n\r\nhow are you today?\r\nI do not know. I guess I am:\n'fine'\r\n\r\n--segment\r\nContent-Type: text/xml; charset=UTF-8\r\nContent-Length: 22\r\n\r\n<llsd><undef /></llsd>\r\n\r\n");
|
|
||||||
std::stringstream istr;
|
|
||||||
istr.str(SERIALIZED_MIME);
|
|
||||||
LLMimeIndex mime;
|
|
||||||
LLMimeParser parser;
|
|
||||||
bool ok = parser.parseIndex(istr, mime);
|
|
||||||
ensure("Parse successful.", ok);
|
|
||||||
ensure("is multipart.", mime.isMultipart());
|
|
||||||
ensure_equals("sub-part count", mime.subPartCount(), 2);
|
|
||||||
ensure_equals("content length", mime.contentLength(), 220);
|
|
||||||
ensure_equals("data offset for multipart", mime.offset(), 72);
|
|
||||||
|
|
||||||
LLMimeIndex mime_plain(mime.subPart(0));
|
|
||||||
ensure_equals(
|
|
||||||
"first part type",
|
|
||||||
mime_plain.contentType(),
|
|
||||||
"text/plain");
|
|
||||||
ensure_equals(
|
|
||||||
"first part content length",
|
|
||||||
mime_plain.contentLength(),
|
|
||||||
55);
|
|
||||||
ensure_equals("first part offset", mime_plain.offset(), 131);
|
|
||||||
|
|
||||||
LLMimeIndex mime_xml(mime.subPart(1));
|
|
||||||
ensure_equals(
|
|
||||||
"second part type",
|
|
||||||
mime_xml.contentType(),
|
|
||||||
"text/xml; charset=UTF-8");
|
|
||||||
ensure_equals(
|
|
||||||
"second part content length",
|
|
||||||
mime_xml.contentLength(),
|
|
||||||
22);
|
|
||||||
ensure_equals("second part offset", mime_xml.offset(), 262);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<> template<>
|
|
||||||
void mime_parse_object_t::test<5>()
|
|
||||||
{
|
|
||||||
// test multi-part with multiple params
|
|
||||||
const std::string SERIALIZED_MIME("Content-Type: multipart/mixed; boundary=segment; comment=\"testing multiple params.\"\r\nContent-Length: 220\r\n\r\n--segment\r\nContent-Type: text/plain\r\nContent-Length: 55\r\n\r\nhow are you today?\r\nI do not know. I guess I am:\n'fine'\r\n\r\n--segment\r\nContent-Type: text/xml; charset=UTF-8\r\nContent-Length: 22\r\n\r\n<llsd><undef /></llsd>\r\n\r\n");
|
|
||||||
std::stringstream istr;
|
|
||||||
istr.str(SERIALIZED_MIME);
|
|
||||||
LLMimeIndex mime;
|
|
||||||
LLMimeParser parser;
|
|
||||||
bool ok = parser.parseIndex(istr, mime);
|
|
||||||
ensure("Parse successful.", ok);
|
|
||||||
ensure("is multipart.", mime.isMultipart());
|
|
||||||
ensure_equals("sub-part count", mime.subPartCount(), 2);
|
|
||||||
ensure_equals("content length", mime.contentLength(), 220);
|
|
||||||
|
|
||||||
LLMimeIndex mime_plain(mime.subPart(0));
|
|
||||||
ensure_equals(
|
|
||||||
"first part type",
|
|
||||||
mime_plain.contentType(),
|
|
||||||
"text/plain");
|
|
||||||
ensure_equals(
|
|
||||||
"first part content length",
|
|
||||||
mime_plain.contentLength(),
|
|
||||||
55);
|
|
||||||
|
|
||||||
LLMimeIndex mime_xml(mime.subPart(1));
|
|
||||||
ensure_equals(
|
|
||||||
"second part type",
|
|
||||||
mime_xml.contentType(),
|
|
||||||
"text/xml; charset=UTF-8");
|
|
||||||
ensure_equals(
|
|
||||||
"second part content length",
|
|
||||||
mime_xml.contentLength(),
|
|
||||||
22);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<> template<>
|
|
||||||
void mime_parse_object_t::test<6>()
|
|
||||||
{
|
|
||||||
// test multi-part with no specified boundary and eof
|
|
||||||
/*
|
|
||||||
Content-Type: multipart/relatedrnContent-Length: 220rnrn--rnContent-Type: text/plainrnContent-Length: 55rnrnhow are you today?rnI do not know. I guess I am:n'fine'rnrn--rnContent-Type: text/xml; charset=UTF-8rnContent-Length: 22rnrn<llsd><undef /></llsd>rnrn
|
|
||||||
*/
|
|
||||||
const std::string SERIALIZED_MIME("Content-Type: multipart/related\r\nContent-Length: 500\r\n\r\n--\r\nContent-Type: text/plain\r\nContent-Length: 55\r\n\r\nhow are you today?\r\nI do not know. I guess I am:\n'fine'\r\n\r\n--\r\nContent-Type: text/xml; charset=UTF-8\r\nContent-Length: 22\r\n\r\n<llsd><undef /></llsd>\r\n\r\n");
|
|
||||||
std::stringstream istr;
|
|
||||||
istr.str(SERIALIZED_MIME);
|
|
||||||
LLMimeIndex mime;
|
|
||||||
LLMimeParser parser;
|
|
||||||
bool ok = parser.parseIndex(istr, mime);
|
|
||||||
ensure("Parse successful.", ok);
|
|
||||||
ensure("is multipart.", mime.isMultipart());
|
|
||||||
ensure_equals("sub-part count", mime.subPartCount(), 2);
|
|
||||||
ensure_equals("content length", mime.contentLength(), 500);
|
|
||||||
ensure_equals("data offset for multipart", mime.offset(), 56);
|
|
||||||
|
|
||||||
LLMimeIndex mime_plain(mime.subPart(0));
|
|
||||||
ensure_equals(
|
|
||||||
"first part type",
|
|
||||||
mime_plain.contentType(),
|
|
||||||
"text/plain");
|
|
||||||
ensure_equals(
|
|
||||||
"first part content length",
|
|
||||||
mime_plain.contentLength(),
|
|
||||||
55);
|
|
||||||
ensure_equals("first part offset", mime_plain.offset(), 108);
|
|
||||||
|
|
||||||
LLMimeIndex mime_xml(mime.subPart(1));
|
|
||||||
ensure_equals(
|
|
||||||
"second part type",
|
|
||||||
mime_xml.contentType(),
|
|
||||||
"text/xml; charset=UTF-8");
|
|
||||||
ensure_equals(
|
|
||||||
"second part content length",
|
|
||||||
mime_xml.contentLength(),
|
|
||||||
22);
|
|
||||||
ensure_equals("second part offset", mime_xml.offset(), 232);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
template<> template<>
|
|
||||||
void mime_parse_object_t::test<>()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
template<> template<>
|
|
||||||
void mime_parse_object_t::test<>()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
template<> template<>
|
|
||||||
void mime_parse_object_t::test<>()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
template<> template<>
|
|
||||||
void mime_parse_object_t::test<>()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user