llmime.cpp
上传用户:king477883
上传日期:2021-03-01
资源大小:9553k
文件大小:14k
源码类别:

游戏引擎

开发平台:

C++ Builder

  1. /** 
  2.  * @file llmime.cpp
  3.  * @author Phoenix
  4.  * @date 2006-12-20
  5.  * @brief Implementation of mime tools.
  6.  *
  7.  * $LicenseInfo:firstyear=2006&license=viewergpl$
  8.  * 
  9.  * Copyright (c) 2006-2010, Linden Research, Inc.
  10.  * 
  11.  * Second Life Viewer Source Code
  12.  * The source code in this file ("Source Code") is provided by Linden Lab
  13.  * to you under the terms of the GNU General Public License, version 2.0
  14.  * ("GPL"), unless you have obtained a separate licensing agreement
  15.  * ("Other License"), formally executed by you and Linden Lab.  Terms of
  16.  * the GPL can be found in doc/GPL-license.txt in this distribution, or
  17.  * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  18.  * 
  19.  * There are special exceptions to the terms and conditions of the GPL as
  20.  * it is applied to this Source Code. View the full text of the exception
  21.  * in the file doc/FLOSS-exception.txt in this software distribution, or
  22.  * online at
  23.  * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  24.  * 
  25.  * By copying, modifying or distributing this software, you acknowledge
  26.  * that you have read and understood your obligations described above,
  27.  * and agree to abide by those obligations.
  28.  * 
  29.  * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  30.  * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  31.  * COMPLETENESS OR PERFORMANCE.
  32.  * $/LicenseInfo$
  33.  */
  34. #include "linden_common.h"
  35. #include "llmime.h"
  36. #include <vector>
  37. #include "llmemorystream.h"
  38. /**
  39.  * Useful constants.
  40.  */
  41. // Headers specified in rfc-2045 will be canonicalized below.
  42. static const std::string CONTENT_LENGTH("Content-Length");
  43. static const std::string CONTENT_TYPE("Content-Type");
  44. static const S32 KNOWN_HEADER_COUNT = 6;
  45. static const std::string KNOWN_HEADER[KNOWN_HEADER_COUNT] =
  46. {
  47. CONTENT_LENGTH,
  48. CONTENT_TYPE,
  49. std::string("MIME-Version"),
  50. std::string("Content-Transfer-Encoding"),
  51. std::string("Content-ID"),
  52. std::string("Content-Description"),
  53. };
  54. // parser helpers
  55. static const std::string MULTIPART("multipart");
  56. static const std::string BOUNDARY("boundary");
  57. static const std::string END_OF_CONTENT_PARAMETER("rn ;t");
  58. static const std::string SEPARATOR_PREFIX("--");
  59. //static const std::string SEPARATOR_SUFFIX("rn");
  60. /*
  61. Content-Type: multipart/mixed; boundary="segment"
  62. Content-Length: 24832
  63. --segment
  64. Content-Type: image/j2c
  65. Content-Length: 23715
  66. <data>
  67. --segment
  68. Content-Type: text/xml; charset=UTF-8
  69. <meta data>
  70. EOF
  71. */
  72. /**
  73.  * LLMimeIndex
  74.  */
  75. /** 
  76.  * @class LLMimeIndex::Impl
  77.  * @brief Implementation details of the mime index class.
  78.  * @see LLMimeIndex
  79.  */
  80. class LLMimeIndex::Impl
  81. {
  82. public:
  83. Impl() : mOffset(-1), mUseCount(1)
  84. {}
  85. Impl(LLSD headers, S32 offset) :
  86. mHeaders(headers), mOffset(offset), mUseCount(1)
  87. {}
  88. public:
  89. LLSD mHeaders;
  90. S32 mOffset;
  91. S32 mUseCount;
  92. typedef std::vector<LLMimeIndex> sub_part_t;
  93. sub_part_t mAttachments;
  94. };
  95. LLSD LLMimeIndex::headers() const
  96. {
  97. return mImpl->mHeaders;
  98. }
  99. S32 LLMimeIndex::offset() const
  100. {
  101. return mImpl->mOffset;
  102. }
  103. S32 LLMimeIndex::contentLength() const
  104. {
  105. // Find the content length in the headers.
  106. S32 length = -1;
  107. LLSD content_length = mImpl->mHeaders[CONTENT_LENGTH];
  108. if(content_length.isDefined())
  109. {
  110. length = content_length.asInteger();
  111. }
  112. return length;
  113. }
  114. std::string LLMimeIndex::contentType() const
  115. {
  116. std::string type;
  117. LLSD content_type = mImpl->mHeaders[CONTENT_TYPE];
  118. if(content_type.isDefined())
  119. {
  120. type = content_type.asString();
  121. }
  122. return type;
  123. }
  124. bool LLMimeIndex::isMultipart() const
  125. {
  126. bool multipart = false;
  127. LLSD content_type = mImpl->mHeaders[CONTENT_TYPE];
  128. if(content_type.isDefined())
  129. {
  130. std::string type = content_type.asString();
  131. int comp = type.compare(0, MULTIPART.size(), MULTIPART);
  132. if(0 == comp)
  133. {
  134. multipart = true;
  135. }
  136. }
  137. return multipart;
  138. }
  139. S32 LLMimeIndex::subPartCount() const
  140. {
  141. return mImpl->mAttachments.size();
  142. }
  143. LLMimeIndex LLMimeIndex::subPart(S32 index) const
  144. {
  145. LLMimeIndex part;
  146. if((index >= 0) && (index < (S32)mImpl->mAttachments.size()))
  147. {
  148. part = mImpl->mAttachments[index];
  149. }
  150. return part;
  151. }
  152. LLMimeIndex::LLMimeIndex() : mImpl(new LLMimeIndex::Impl)
  153. {
  154. }
  155. LLMimeIndex::LLMimeIndex(LLSD headers, S32 content_offset) :
  156. mImpl(new LLMimeIndex::Impl(headers, content_offset))
  157. {
  158. }
  159. LLMimeIndex::LLMimeIndex(const LLMimeIndex& mime) :
  160. mImpl(mime.mImpl)
  161. {
  162. ++mImpl->mUseCount;
  163. }
  164. LLMimeIndex::~LLMimeIndex()
  165. {
  166. if(0 == --mImpl->mUseCount)
  167. {
  168. delete mImpl;
  169. }
  170. }
  171. LLMimeIndex& LLMimeIndex::operator=(const LLMimeIndex& mime)
  172. {
  173. // Increment use count first so that we handle self assignment
  174. // automatically.
  175. ++mime.mImpl->mUseCount;
  176. if(0 == --mImpl->mUseCount)
  177. {
  178. delete mImpl;
  179. }
  180. mImpl = mime.mImpl;
  181. return *this;
  182. }
  183. bool LLMimeIndex::attachSubPart(LLMimeIndex sub_part)
  184. {
  185. // *FIX: Should we check for multi-part?
  186. if(mImpl->mAttachments.size() < S32_MAX)
  187. {
  188. mImpl->mAttachments.push_back(sub_part);
  189. return true;
  190. }
  191. return false;
  192. }
  193. /**
  194.  * LLMimeParser
  195.  */
  196. /** 
  197.  * @class LLMimeParser::Impl
  198.  * @brief Implementation details of the mime parser class.
  199.  * @see LLMimeParser
  200.  */
  201. class LLMimeParser::Impl
  202. {
  203. public:
  204. // @brief Constructor.
  205. Impl();
  206. // @brief Reset this for a new parse.
  207. void reset();
  208. /** 
  209.  * @brief Parse a mime entity to find the index information.
  210.  *
  211.  * This method will scan the istr until a single complete mime
  212.  * entity is read, an EOF, or limit bytes have been scanned. The
  213.  * istr will be modified by this parsing, so pass in a temporary
  214.  * stream or rewind/reset the stream after this call.
  215.  * @param istr An istream which contains a mime entity.
  216.  * @param limit The maximum number of bytes to scan.
  217.  * @param separator The multipart separator if it is known.
  218.  * @param is_subpart Set true if parsing a multipart sub part.
  219.  * @param index[out] The parsed output.
  220.  * @return Returns true if an index was parsed and no errors occurred.
  221.  */
  222. bool parseIndex(
  223. std::istream& istr,
  224. S32 limit,
  225. const std::string& separator,
  226. bool is_subpart,
  227. LLMimeIndex& index);
  228. protected:
  229. /**
  230.  * @brief parse the headers.
  231.  *
  232.  * At the end of a successful parse, mScanCount will be at the
  233.  * start of the content.
  234.  * @param istr The input stream.
  235.  * @param limit maximum number of bytes to process
  236.  * @param headers[out] A map of the headers found.
  237.  * @return Returns true if the parse was successful.
  238.  */
  239. bool parseHeaders(std::istream& istr, S32 limit, LLSD& headers);
  240. /**
  241.  * @brief Figure out the separator string from a content type header.
  242.  * 
  243.  * @param multipart_content_type The content type value from the headers.
  244.  * @return Returns the separator string.
  245.  */
  246. std::string findSeparator(std::string multipart_content_type);
  247. /**
  248.  * @brief Scan through istr past the separator.
  249.  *
  250.  * @param istr The input stream.
  251.  * @param limit Maximum number of bytes to scan.
  252.  * @param separator The multipart separator.
  253.  */
  254. void scanPastSeparator(
  255. std::istream& istr,
  256. S32 limit,
  257. const std::string& separator);
  258. /**
  259.  * @brief Scan through istr past the content of the current mime part.
  260.  *
  261.  * @param istr The input stream.
  262.  * @param limit Maximum number of bytes to scan.
  263.  * @param headers The headers for this mime part.
  264.  * @param separator The multipart separator if known.
  265.  */
  266. void scanPastContent(
  267. std::istream& istr,
  268. S32 limit,
  269. LLSD headers,
  270. const std::string separator);
  271. /**
  272.  * @brief Eat CRLF.
  273.  *
  274.  * This method has no concept of the limit, so ensure you have at
  275.  * least 2 characters left to eat before hitting the limit. This
  276.  * method will increment mScanCount as it goes.
  277.  * @param istr The input stream.
  278.  * @return Returns true if CRLF was found and consumed off of istr.
  279.  */
  280. bool eatCRLF(std::istream& istr);
  281. // @brief Returns true if parsing should continue.
  282. bool continueParse() const { return (!mError && mContinue); }
  283. // @brief anonymous enumeration for parse buffer size.
  284. enum
  285. {
  286. LINE_BUFFER_LENGTH = 1024
  287. };
  288. protected:
  289. S32 mScanCount;
  290. bool mContinue;
  291. bool mError;
  292. char mBuffer[LINE_BUFFER_LENGTH];
  293. };
  294. LLMimeParser::Impl::Impl()
  295. {
  296. reset();
  297. }
  298. void LLMimeParser::Impl::reset()
  299. {
  300. mScanCount = 0;
  301. mContinue = true;
  302. mError = false;
  303. mBuffer[0] = '';
  304. }
  305. bool LLMimeParser::Impl::parseIndex(
  306. std::istream& istr,
  307. S32 limit,
  308. const std::string& separator,
  309. bool is_subpart,
  310. LLMimeIndex& index)
  311. {
  312. LLSD headers;
  313. bool parsed_something = false;
  314. if(parseHeaders(istr, limit, headers))
  315. {
  316. parsed_something = true;
  317. LLMimeIndex mime(headers, mScanCount);
  318. index = mime;
  319. if(index.isMultipart())
  320. {
  321. // Figure out the separator, scan past it, and recurse.
  322. std::string ct = headers[CONTENT_TYPE].asString();
  323. std::string sep = findSeparator(ct);
  324. scanPastSeparator(istr, limit, sep);
  325. while(continueParse() && parseIndex(istr, limit, sep, true, mime))
  326. {
  327. index.attachSubPart(mime);
  328. }
  329. }
  330. else
  331. {
  332. // Scan to the end of content.
  333. scanPastContent(istr, limit, headers, separator);
  334. if(is_subpart)
  335. {
  336. scanPastSeparator(istr, limit, separator);
  337. }
  338. }
  339. }
  340. if(mError) return false;
  341. return parsed_something;
  342. }
  343. bool LLMimeParser::Impl::parseHeaders(
  344. std::istream& istr,
  345. S32 limit,
  346. LLSD& headers)
  347. {
  348. while(continueParse())
  349. {
  350. // Get the next line.
  351. // We subtract 1 from the limit so that we make sure
  352. // not to read past limit when we get() the newline.
  353. S32 max_get = llmin((S32)LINE_BUFFER_LENGTH, limit - mScanCount - 1);
  354. istr.getline(mBuffer, max_get, 'r');
  355. mScanCount += istr.gcount();
  356. int c = istr.get();
  357. if(EOF == c)
  358. {
  359. mContinue = false;
  360. return false;
  361. }
  362. ++mScanCount;
  363. if(c != 'n')
  364. {
  365. mError = true;
  366. return false;
  367. }
  368. if(mScanCount >= limit)
  369. {
  370. mContinue = false;
  371. }
  372. // Check if that's the end of headers.
  373. if('' == mBuffer[0])
  374. {
  375. break;
  376. }
  377. // Split out the name and value.
  378. // *NOTE: The use of strchr() here is safe since mBuffer is
  379. // guaranteed to be NULL terminated from the call to getline()
  380. // above.
  381. char* colon = strchr(mBuffer, ':');
  382. if(!colon)
  383. {
  384. mError = true;
  385. return false;
  386. }
  387. // Cononicalize the name part, and store the name: value in
  388. // the headers structure. We do this by iterating through
  389. // 'known' headers and replacing the value found with the
  390. // correct one.
  391. // *NOTE: Not so efficient, but iterating through a small
  392. // subset should not be too much of an issue.
  393. std::string name(mBuffer, colon++ - mBuffer);
  394. while(isspace(*colon)) ++colon;
  395. std::string value(colon);
  396. for(S32 ii = 0; ii < KNOWN_HEADER_COUNT; ++ii)
  397. {
  398. if(0 == LLStringUtil::compareInsensitive(name, KNOWN_HEADER[ii]))
  399. {
  400. name = KNOWN_HEADER[ii];
  401. break;
  402. }
  403. }
  404. headers[name] = value;
  405. }
  406. if(headers.isUndefined()) return false;
  407. return true;
  408. }
  409. std::string LLMimeParser::Impl::findSeparator(std::string header)
  410. {
  411. //                               01234567890
  412. //Content-Type: multipart/mixed; boundary="segment"
  413. std::string separator;
  414. std::string::size_type pos = header.find(BOUNDARY);
  415. if(std::string::npos == pos) return separator;
  416. pos += BOUNDARY.size() + 1;
  417. std::string::size_type end;
  418. if(header[pos] == '"')
  419. {
  420. // the boundary is quoted, find the end from pos, and take the
  421. // substring.
  422. end = header.find('"', ++pos);
  423. if(std::string::npos == end)
  424. {
  425. // poorly formed boundary.
  426. mError = true;
  427. }
  428. }
  429. else
  430. {
  431. // otherwise, it's every character until a whitespace, end of
  432. // line, or another parameter begins.
  433. end = header.find_first_of(END_OF_CONTENT_PARAMETER, pos);
  434. if(std::string::npos == end)
  435. {
  436. // it goes to the end of the string.
  437. end = header.size();
  438. }
  439. }
  440. if(!mError) separator = header.substr(pos, end - pos);
  441. return separator;
  442. }
  443. void LLMimeParser::Impl::scanPastSeparator(
  444. std::istream& istr,
  445. S32 limit,
  446. const std::string& sep)
  447. {
  448. std::ostringstream ostr;
  449. ostr << SEPARATOR_PREFIX << sep;
  450. std::string separator = ostr.str();
  451. bool found_separator = false;
  452. while(!found_separator && continueParse())
  453. {
  454. // Subtract 1 from the limit so that we make sure not to read
  455. // past limit when we get() the newline.
  456. S32 max_get = llmin((S32)LINE_BUFFER_LENGTH, limit - mScanCount - 1);
  457. istr.getline(mBuffer, max_get, 'r');
  458. mScanCount += istr.gcount();
  459. if(istr.gcount() >= LINE_BUFFER_LENGTH - 1)
  460. {
  461. // that's way too long to be a separator, so ignore it.
  462. continue;
  463. }
  464. int c = istr.get();
  465. if(EOF == c)
  466. {
  467. mContinue = false;
  468. return;
  469. }
  470. ++mScanCount;
  471. if(c != 'n')
  472. {
  473. mError = true;
  474. return;
  475. }
  476. if(mScanCount >= limit)
  477. {
  478. mContinue = false;
  479. }
  480. if(0 == LLStringUtil::compareStrings(std::string(mBuffer), separator))
  481. {
  482. found_separator = true;
  483. }
  484. }
  485. }
  486. void LLMimeParser::Impl::scanPastContent(
  487. std::istream& istr,
  488. S32 limit,
  489. LLSD headers,
  490. const std::string separator)
  491. {
  492. if(headers.has(CONTENT_LENGTH))
  493. {
  494. S32 content_length = headers[CONTENT_LENGTH].asInteger();
  495. // Subtract 2 here for the rn after the content.
  496. S32 max_skip = llmin(content_length, limit - mScanCount - 2);
  497. istr.ignore(max_skip);
  498. mScanCount += max_skip;
  499. // *NOTE: Check for hitting the limit and eof here before
  500. // checking for the trailing EOF, because our mime parser has
  501. // to gracefully handle incomplete mime entites.
  502. if((mScanCount >= limit) || istr.eof())
  503. {
  504. mContinue = false;
  505. }
  506. else if(!eatCRLF(istr))
  507. {
  508. mError = true;
  509. return;
  510. }
  511. }
  512. }
  513. bool LLMimeParser::Impl::eatCRLF(std::istream& istr)
  514. {
  515. int c = istr.get();
  516. ++mScanCount;
  517. if(c != 'r')
  518. {
  519. return false;
  520. }
  521. c = istr.get();
  522. ++mScanCount;
  523. if(c != 'n')
  524. {
  525. return false;
  526. }
  527. return true;
  528. }
  529. LLMimeParser::LLMimeParser() : mImpl(* new LLMimeParser::Impl)
  530. {
  531. }
  532. LLMimeParser::~LLMimeParser()
  533. {
  534. delete & mImpl;
  535. }
  536. void LLMimeParser::reset()
  537. {
  538. mImpl.reset();
  539. }
  540. bool LLMimeParser::parseIndex(std::istream& istr, LLMimeIndex& index)
  541. {
  542. std::string separator;
  543. return mImpl.parseIndex(istr, S32_MAX, separator, false, index);
  544. }
  545. bool LLMimeParser::parseIndex(
  546. const std::vector<U8>& buffer,
  547. LLMimeIndex& index)
  548. {
  549. LLMemoryStream mstr(&buffer[0], buffer.size());
  550. return parseIndex(mstr, buffer.size() + 1, index);
  551. }
  552. bool LLMimeParser::parseIndex(
  553. std::istream& istr,
  554. S32 limit,
  555. LLMimeIndex& index)
  556. {
  557. std::string separator;
  558. return mImpl.parseIndex(istr, limit, separator, false, index);
  559. }
  560. bool LLMimeParser::parseIndex(const U8* buffer, S32 length, LLMimeIndex& index)
  561. {
  562. LLMemoryStream mstr(buffer, length);
  563. return parseIndex(mstr, length + 1, index);
  564. }
  565. /*
  566. bool LLMimeParser::verify(std::istream& isr, LLMimeIndex& index) const
  567. {
  568. return false;
  569. }
  570. bool LLMimeParser::verify(U8* buffer, S32 length, LLMimeIndex& index) const
  571. {
  572. LLMemoryStream mstr(buffer, length);
  573. return verify(mstr, index);
  574. }
  575. */