httppars.cpp
上传用户:dangjiwu
上传日期:2013-07-19
资源大小:42019k
文件大小:15k
源码类别:

Symbian

开发平台:

Visual C++

  1. /* ***** BEGIN LICENSE BLOCK *****
  2.  * Source last modified: $Id: httppars.cpp,v 1.3.32.1 2004/07/09 02:04:59 hubbe Exp $
  3.  * 
  4.  * Portions Copyright (c) 1995-2004 RealNetworks, Inc. All Rights Reserved.
  5.  * 
  6.  * The contents of this file, and the files included with this file,
  7.  * are subject to the current version of the RealNetworks Public
  8.  * Source License (the "RPSL") available at
  9.  * http://www.helixcommunity.org/content/rpsl unless you have licensed
  10.  * the file under the current version of the RealNetworks Community
  11.  * Source License (the "RCSL") available at
  12.  * http://www.helixcommunity.org/content/rcsl, in which case the RCSL
  13.  * will apply. You may also obtain the license terms directly from
  14.  * RealNetworks.  You may not use this file except in compliance with
  15.  * the RPSL or, if you have a valid RCSL with RealNetworks applicable
  16.  * to this file, the RCSL.  Please see the applicable RPSL or RCSL for
  17.  * the rights, obligations and limitations governing use of the
  18.  * contents of the file.
  19.  * 
  20.  * Alternatively, the contents of this file may be used under the
  21.  * terms of the GNU General Public License Version 2 or later (the
  22.  * "GPL") in which case the provisions of the GPL are applicable
  23.  * instead of those above. If you wish to allow use of your version of
  24.  * this file only under the terms of the GPL, and not to allow others
  25.  * to use your version of this file under the terms of either the RPSL
  26.  * or RCSL, indicate your decision by deleting the provisions above
  27.  * and replace them with the notice and other provisions required by
  28.  * the GPL. If you do not delete the provisions above, a recipient may
  29.  * use your version of this file under the terms of any one of the
  30.  * RPSL, the RCSL or the GPL.
  31.  * 
  32.  * This file is part of the Helix DNA Technology. RealNetworks is the
  33.  * developer of the Original Code and owns the copyrights in the
  34.  * portions it created.
  35.  * 
  36.  * This file, and the files included with this file, is distributed
  37.  * and made available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY
  38.  * KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS
  39.  * ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES
  40.  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET
  41.  * ENJOYMENT OR NON-INFRINGEMENT.
  42.  * 
  43.  * Technology Compatibility Kit Test Suite(s) Location:
  44.  *    http://www.helixcommunity.org/content/tck
  45.  * 
  46.  * Contributor(s):
  47.  * 
  48.  * ***** END LICENSE BLOCK ***** */
  49. //#include "hlxclib/stdlib.h"
  50. #include "hxcom.h"
  51. #include "hxtypes.h"
  52. #include "hxassert.h"
  53. #include "debug.h"
  54. #include "hxstrutl.h"
  55. #include "hxstring.h"
  56. #include "chxpckts.h"
  57. #include "hxauth.h"
  58. #include "httppars.h"
  59. #include "httpmsg.h"
  60. #include "hxheap.h"
  61. #ifdef _DEBUG
  62. #undef HX_THIS_FILE
  63. static const char HX_THIS_FILE[] = __FILE__;
  64. #endif
  65. HTTPParser::HTTPParser()
  66. {
  67. }
  68. HTTPParser::~HTTPParser()
  69. {
  70.     clearMessageLines();
  71. }
  72. /*
  73.  * Extract major/minor version info
  74.  */
  75. int 
  76. HTTPParser::parseProtocolVersion(const CHXString& prot,
  77.     int& majorVersion, int& minorVersion)
  78. {
  79.     if(strncasecmp(prot, "HTTP/", 5) != 0)
  80.      return 0;
  81.     int nVerOffset = prot.Find('.');
  82.     if(nVerOffset > 5)
  83.     {
  84. CHXString majVersion = prot.Mid(5, nVerOffset-5);
  85. majorVersion = (int)strtol(majVersion, 0, 10);
  86. CHXString minVersion = prot.Mid(nVerOffset+1);
  87. minorVersion = (int)strtol(minVersion, 0, 10);
  88. return 1;
  89.     }
  90.     return 0;
  91. }
  92. /*
  93.  * Parse option in form 'name[=value] *[;name[=value]]'
  94.  */
  95. int 
  96. HTTPParser::parseHeaderValue(const char* pValue, MIMEHeader* pHeader)
  97. {
  98.     if(strlen(pValue) == 0)
  99. return 0;
  100.     MIMEInputStream input(pValue, strlen(pValue));
  101.     MIMEScanner scanner(input);
  102.     MIMEHeaderValue* pHeaderValue = 0;
  103.     MIMEToken tok = scanner.nextToken(";");
  104.     while(tok.hasValue())
  105.     {
  106. if(!pHeaderValue)
  107. {
  108.     CHXString attribute = tok.value();
  109.     pHeaderValue = new MIMEHeaderValue;
  110.     if(tok.lastChar() == '=')
  111.     {
  112. tok = scanner.nextToken(";");
  113. CHXString value = tok.value();
  114. pHeaderValue->addParameter(attribute, value);
  115.     }
  116.     else
  117.     {
  118. pHeaderValue->addParameter(attribute);
  119.     }
  120. }
  121. else if(tok.lastChar() == '=')
  122. {
  123.     CHXString attribute = tok.value();
  124.     tok = scanner.nextToken(";");
  125.     CHXString value = tok.value();
  126.     pHeaderValue->addParameter(attribute, value);
  127. }
  128. else
  129. {
  130.     CHXString attribute = tok.value();
  131.     pHeaderValue->addParameter(attribute, "");
  132. }
  133. tok = scanner.nextToken("=;");
  134.     }
  135.     if(pHeaderValue)
  136. pHeader->addHeaderValue(pHeaderValue);
  137.     return 0;
  138. }
  139. int
  140. HTTPParser::parseWWWAuthenticateHeaderValues(const char* pValue,
  141.                                              MIMEHeader* pHeader)
  142. {
  143.     MIMEInputStream input(pValue, strlen(pValue));
  144.     MIMEScanner scanner(input);
  145.     IHXValues* authValues;
  146.     /*
  147.       char* pNonce = 0;
  148.       char* pRealm = 0;
  149.       char* pOpaque= 0;
  150.       */
  151.     MIMEToken nextTok = scanner.nextToken(" ");
  152.     if(strcasecmp(nextTok.value(), "Digest") == 0)
  153.     {
  154.         authValues = new CHXHeader;
  155.         authValues->AddRef();
  156.         authValues->SetPropertyULONG32("AuthType", HX_AUTH_DIGEST);
  157.         while(nextTok.hasValue())
  158.         {
  159.             nextTok = scanner.nextToken("=,");
  160.             if(strcasecmp(nextTok.value(), "nonce") == 0)
  161.             {
  162.                 nextTok = scanner.nextToken("=,");
  163. CHXBuffer* pBuf = new CHXBuffer;
  164. pBuf->AddRef();
  165. pBuf->Set((const BYTE*)(const char*)nextTok.value(),
  166.     nextTok.value().GetLength()+1);
  167.                 authValues->SetPropertyCString("Nonce", pBuf);
  168. pBuf->Release();
  169.             }
  170.             else if(strcasecmp(nextTok.value(), "realm") == 0)
  171.             {
  172.                 nextTok = scanner.nextToken("=,");
  173. CHXBuffer* pBuf = new CHXBuffer;
  174. pBuf->AddRef();
  175. pBuf->Set((const BYTE*)(const char*)nextTok.value(),
  176.     nextTok.value().GetLength()+1);
  177.                 authValues->SetPropertyCString("Realm", pBuf);
  178. pBuf->Release();
  179.             }
  180.             else if(strcasecmp(nextTok.value(), "opaque") == 0)
  181.             {
  182.                 nextTok = scanner.nextToken("=,");
  183. CHXBuffer* pBuf = new CHXBuffer;
  184. pBuf->AddRef();
  185. pBuf->Set((const BYTE*)(const char*)nextTok.value(),
  186.     nextTok.value().GetLength()+1);
  187.                 authValues->SetPropertyCString("Opaque", pBuf);
  188. pBuf->Release();
  189.             }
  190.         }
  191.         pHeader->addHeaderValue
  192.             (new HTTPAuthentication(authValues));
  193.         authValues->Release();
  194.     }
  195.     else if(strcasecmp(nextTok.value(), "Basic") == 0)
  196.     {
  197.         authValues = new CHXHeader();
  198.         authValues->AddRef();
  199.         authValues->SetPropertyULONG32("AuthType", HX_AUTH_BASIC);
  200.         while(nextTok.hasValue())
  201.         {
  202.             nextTok = scanner.nextToken("=,");
  203.             if(strcasecmp(nextTok.value(), "realm") == 0)
  204.             {
  205.                 nextTok = scanner.nextToken("=,");
  206.                 char * realmstr = new char[strlen(nextTok.value()) + 1];
  207.                 char* valstart, *valend;
  208.                 valstart = (char*)strchr(nextTok.value(), '"');
  209.                 valend = (char*)strrchr(nextTok.value(), '"');
  210.                 if(valstart && valend && valstart != valend)
  211.                 {
  212.                     valstart++;
  213.                     memcpy(realmstr, valstart, valend - valstart);
  214.                     realmstr[valend - valstart] = 0;
  215.                 }
  216.                 else
  217.                 {
  218.                     strcpy(realmstr, nextTok.value());
  219.                 }
  220. CHXBuffer* pBuf = new CHXBuffer;
  221. pBuf->AddRef();
  222. pBuf->Set((const BYTE*)realmstr, strlen(realmstr)+1);
  223.                 authValues->SetPropertyCString("Realm", pBuf);
  224. pBuf->Release();
  225.                 delete [] realmstr;
  226.             }
  227.         }
  228.         pHeader->addHeaderValue(new HTTPAuthentication(authValues));
  229.         authValues->Release();
  230.     }
  231.     else
  232.     {
  233. // Just add un-parsed value
  234.         pHeader->addHeaderValue(pValue);
  235.     }
  236.     return 0;
  237. }
  238. /*
  239.  * Parse header values as list of comma separated values
  240.  */
  241. int 
  242. HTTPParser::defaultParseHeaderValues(const char* pValue, MIMEHeader* pHeader)
  243. {
  244.     MIMEInputStream input(pValue, strlen(pValue));
  245.     MIMEScanner scanner(input);
  246.     
  247.     MIMEToken nextTok = scanner.nextToken(",");
  248.     while(nextTok.hasValue())
  249.     {
  250. parseHeaderValue(nextTok.value(), pHeader);
  251. if((nextTok.lastChar() == MIMEToken::T_EOL) ||
  252.    (nextTok.lastChar() == MIMEToken::T_EOF))
  253.     return 0;
  254. nextTok = scanner.nextToken(",");
  255.     }
  256.     return 0;
  257. }
  258. /*
  259.  * construct an MIMEHeader and add header values to it
  260.  * format: 'HeaderName: option, option=value, option'
  261.  */
  262. MIMEHeader* 
  263. HTTPParser::parseHeader(CHXString& str)
  264. {
  265.     MIMEHeader* pHeader = 0;
  266.     MIMEInputStream input(str);
  267.     MIMEScanner scanner(input);
  268.     MIMEToken nextTok = scanner.nextToken(":");
  269.     if(nextTok.hasValue())
  270.     {
  271. pHeader = new MIMEHeader(nextTok.value());
  272. nextTok = scanner.nextToken("n");
  273. if(strcasecmp(pHeader->name(), "WWW-Authenticate") == 0)
  274. {
  275.     parseWWWAuthenticateHeaderValues(nextTok.value(), pHeader);
  276. }
  277. else
  278. {
  279.     defaultParseHeaderValues(nextTok.value(), pHeader);
  280. }
  281.     }
  282.     return pHeader;
  283. }
  284. /*
  285.  * Parse request line in format 'METHOD URL VERSION SEQ_NO'
  286.  */
  287. HTTPRequestMessage*
  288. HTTPParser::parseRequestLine(CHXString& str)
  289. {
  290.     int majorVersion, minorVersion;
  291.     HTTPRequestMessage* pReqMsg = 0;
  292.     MIMEInputStream input(str);
  293.     MIMEScanner scanner(input);
  294.     // build message
  295.     MIMEToken nextTok = scanner.nextToken();
  296.     if(strcasecmp(nextTok.value(), "GET") == 0)
  297.     {
  298. pReqMsg = new HTTPGetMessage;
  299.     }
  300.     else if(strcasecmp(nextTok.value(), "HEAD") == 0)
  301.     {
  302. pReqMsg = new HTTPHeadMessage;
  303.     }
  304.     else if(strcasecmp(nextTok.value(), "POST") == 0)
  305.     {
  306. pReqMsg = new HTTPPostMessage;
  307.     }
  308.     else
  309.     {
  310. pReqMsg = new HTTPUnknownMessage;
  311.     }
  312.     // get URL
  313.     nextTok = scanner.nextToken("t n");
  314.     pReqMsg->setURL(nextTok.value());
  315.     // get version info
  316.     nextTok = scanner.nextToken();
  317.     if(parseProtocolVersion(nextTok.value(), majorVersion, minorVersion))
  318.     {
  319. pReqMsg->setVersion(majorVersion, minorVersion);
  320.     }
  321.     else
  322.     {
  323. pReqMsg->setVersion(0,0);
  324.     }
  325.     return pReqMsg;
  326. }
  327. /*
  328.  * Parse response line in format 'VERSION ERR_CODE SEQ_NO ERR_MSG'
  329.  */
  330. HTTPResponseMessage*
  331. HTTPParser::parseResponseLine(CHXString& str)
  332. {
  333.     int majorVersion, minorVersion;
  334.     HTTPResponseMessage* pRespMsg = 0;
  335.     MIMEInputStream input(str);
  336.     MIMEScanner scanner(input);
  337.     MIMEToken nextTok = scanner.nextToken();
  338.     pRespMsg = new HTTPResponseMessage;
  339.     if(parseProtocolVersion(nextTok.value(), 
  340. majorVersion, minorVersion))
  341.     {
  342. pRespMsg->setVersion(majorVersion, minorVersion);
  343.     }
  344.     else
  345.     {
  346. pRespMsg->setVersion(0,0);
  347.     }
  348.     // get error code
  349.     nextTok = scanner.nextToken();
  350.     pRespMsg->setErrorCode(nextTok.value());
  351.     // get error message
  352.     nextTok = scanner.nextToken("n"); // go to EOL
  353.     pRespMsg->setErrorMsg(nextTok.value());
  354.     return pRespMsg;
  355. }
  356. /*
  357.  * Parse response message
  358.  */
  359. HTTPMessage* 
  360. HTTPParser::parseResponse()
  361. {
  362.     HTTPResponseMessage* pRespMsg = 0;
  363.     
  364.     LISTPOSITION pos = m_msglines.GetHeadPosition();
  365.     CHXString* pStr = (CHXString*)m_msglines.GetNext(pos);
  366.     pRespMsg = parseResponseLine(*pStr);
  367.     if(!pRespMsg)
  368. return 0;
  369.     while(pos)
  370.     {
  371. pStr = (CHXString*)m_msglines.GetNext(pos);
  372. MIMEHeader* pHeader = parseHeader(*pStr);
  373. if(pHeader)
  374.     pRespMsg->addHeader(pHeader);
  375.     }
  376.     return pRespMsg;
  377. }
  378. /*
  379.  * Parse request message
  380.  */
  381. HTTPMessage* 
  382. HTTPParser::parseRequest()
  383. {
  384.     HTTPRequestMessage* pReqMsg = 0;
  385.     
  386.     LISTPOSITION pos = m_msglines.GetHeadPosition();
  387.     CHXString* pStr = (CHXString*)m_msglines.GetNext(pos);
  388.     pReqMsg = parseRequestLine(*pStr);
  389.     if(!pReqMsg)
  390. return 0;
  391.     if(pReqMsg->majorVersion() < 0)
  392. return pReqMsg;
  393.     while(pos)
  394.     {
  395. pStr = (CHXString*)m_msglines.GetNext(pos);
  396. MIMEHeader* pHeader = parseHeader(*pStr);
  397. if(pHeader)
  398.     pReqMsg->addHeader(pHeader);
  399.     }
  400.     return pReqMsg;
  401. }
  402. /*
  403.  * Add each line in message to list m_msglines.
  404.  * Look for two carriage returns to delimit
  405.  * message header.
  406.  */
  407. int 
  408. HTTPParser::scanMessageHeader(const char* pMsg, UINT32 nMsgLen)
  409. {
  410.     // first, get rid of any leading whitespace and <CR><LF> chars
  411.     const char* pCh = pMsg;
  412.     while(*pCh == 'n' || *pCh == 'r' || *pCh == ' ' || *pCh == 't')
  413.     {
  414. pCh++;
  415.     }
  416.     UINT32 offset = pCh - pMsg;
  417.     if(offset > nMsgLen)
  418.     {
  419. return 0;
  420.     }
  421.     MIMEInputStream input(pMsg, nMsgLen - offset);
  422.     MIMEScanner scanner(input);
  423.     MIMEToken tok;
  424.     int gotEOL = 0;
  425.     UINT32 scanOffset = 0;
  426.     do
  427.     {
  428. tok = scanner.nextToken("n");
  429. m_msglines.AddTail((void*)(new CHXString((const char*)tok.value())));
  430. if(tok.lastChar() == MIMEToken::T_EOL)
  431. {
  432.     if(gotEOL && !tok.hasValue())
  433.     {
  434. scanOffset = scanner.offset();
  435. break;
  436.     }
  437.     else
  438.     {
  439. gotEOL = 1;
  440.     }
  441. }
  442. else
  443. {
  444.     gotEOL = 0;
  445. }
  446.     } while(tok.lastChar() != MIMEToken::T_EOF);
  447.     if(scanOffset == 0)
  448.     {
  449. return 0;
  450.     }
  451.     else
  452.     {
  453. return HX_SAFEINT(scanOffset + offset);
  454.     }
  455. }
  456. /*
  457.  * Parse message pointed to by pMsg with length nMsgLen.
  458.  * If not a complete message, return 0, otherwise return
  459.  * HTTPMessage pointer.
  460.  */
  461. HTTPMessage* 
  462. HTTPParser::parse(const char* pMsg, UINT32& nMsgLen)
  463. {
  464.     HTTPMessage* pHTTPMsg = 0;
  465.     clearMessageLines();
  466.     int msgOffset = scanMessageHeader(pMsg, nMsgLen);
  467.     if(msgOffset > 0)
  468.     {
  469. if(m_msglines.GetCount() == 0)
  470. {
  471.     nMsgLen = 0;
  472.     return 0;
  473. }
  474. CHXString* str = (CHXString*)m_msglines.GetHead();
  475. if(strncasecmp((*str), "HTTP/", 5) == 0)
  476. {
  477.     pHTTPMsg = parseResponse();
  478. }
  479. else 
  480. {
  481.     pHTTPMsg = parseRequest();
  482. }
  483. if(pHTTPMsg)
  484. {
  485.     nMsgLen = msgOffset;
  486. }
  487.     }
  488.     else
  489.     {
  490. //nMsgLen = 0;
  491. /* Might be a HTTP/0.9 request.  No extra blank line. Drat. */
  492. if(m_msglines.GetCount() == 0)
  493. {
  494.     nMsgLen = 0;
  495.     return 0;
  496. }
  497. CHXString* str = (CHXString*)m_msglines.GetHead();
  498. pHTTPMsg = parseRequest();
  499. if(!pHTTPMsg || pHTTPMsg->majorVersion() > 0)
  500. {
  501.     nMsgLen = 0;
  502.     delete pHTTPMsg;
  503.     pHTTPMsg = 0;
  504. }
  505.     }
  506.     return pHTTPMsg;
  507. }
  508. /*
  509.  * Delete contents of m_msglines
  510.  */
  511. void 
  512. HTTPParser::clearMessageLines()
  513. {
  514.     LISTPOSITION pos = m_msglines.GetHeadPosition();
  515.     while(pos)
  516.     {
  517. CHXString* str = (CHXString*)m_msglines.GetNext(pos);
  518. delete str;
  519.     }
  520.     m_msglines.RemoveAll();
  521. }