httppars.cpp
上传用户:zhongxx05
上传日期:2007-06-06
资源大小:33641k
文件大小:14k
源码类别:

Symbian

开发平台:

C/C++

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