REQSOCK.CPP
上传用户:btxinjin
上传日期:2007-01-04
资源大小:83k
文件大小:35k
源码类别:

Web服务器

开发平台:

Visual C++

  1. // ReqSock.cpp : implementation of the CRequestSocket class
  2. //
  3. // This is a part of the Microsoft Foundation Classes C++ library.
  4. // Copyright (C) 1997-1998 Microsoft Corporation
  5. // All rights reserved.
  6. //
  7. // This source code is only intended as a supplement to the
  8. // Microsoft Foundation Classes Reference and related
  9. // electronic documentation provided with the library.
  10. // See these sources for detailed information regarding the
  11. // Microsoft Foundation Classes product.
  12. #include "stdafx.h"
  13. #include "HttpSvr.h"
  14. #include "HttpDoc.h"
  15. #include "Http.h"
  16. #include "ReqSock.h"
  17. #include "Request.h"
  18. #include "resource.h"
  19. #ifdef _DEBUG
  20. #define new DEBUG_NEW
  21. #undef THIS_FILE
  22. static char THIS_FILE[] = __FILE__;
  23. #endif
  24. IMPLEMENT_DYNCREATE(CRequestSocket, CAsyncSocket)
  25. #define CRLF    "x0dx0a"
  26. SECURITY_ATTRIBUTES g_sa = {sizeof(SECURITY_ATTRIBUTES),NULL,TRUE};
  27. CRequestSocket::CRequestSocket( void )
  28. {
  29. }
  30. CRequestSocket::CRequestSocket( CHttpSvrDoc* pDoc )
  31. {
  32. #ifdef IMPL_CGI
  33. m_pThread = NULL;
  34. m_pCancel = NULL;
  35. #endif // IMPL_CGI
  36. m_bKilled = FALSE;
  37. m_nRefs = 1;
  38. m_reqStatus = REQ_REQUEST;
  39. m_buf.SetSize( 1024 );
  40. m_cbOut = 0;
  41. m_hFile = INVALID_HANDLE_VALUE;
  42. m_pRequest = NULL;
  43. m_pDoc = pDoc;
  44. }
  45. CRequestSocket::~CRequestSocket( void )
  46. {
  47. // JIC....
  48. #ifdef IMPL_CGI
  49. if ( m_pCancel )
  50. {
  51. if ( m_pThread )
  52. {
  53. DWORD dwCode;
  54. // signal a cancel if still running....
  55. if ( ::GetExitCodeThread( m_pThread->m_hThread, &dwCode )
  56. && dwCode == STILL_ACTIVE )
  57. {
  58. // signal a cancel....
  59. m_pCancel->SetEvent();
  60. // wait for the thread to die....
  61. WaitForSingleObject( m_pThread->m_hThread, INFINITE );
  62. }
  63. // kill the object...
  64. delete m_pThread;
  65. }
  66. delete m_pCancel;
  67. }
  68. #endif // IMPL_CGI
  69. if ( m_hFile )
  70. CloseHandle( m_hFile );
  71. if ( m_pRequest )
  72. {
  73. // release our hold on the request object....
  74. m_pRequest->m_bDone = TRUE;
  75. m_pRequest->Release();
  76. }
  77. }
  78. void CRequestSocket::OnReceive(int nErrorCode)
  79. {
  80. if ( m_pRequest == NULL )
  81. {
  82. // new request....
  83. m_pRequest = new CRequest;
  84. m_bKeepOpen = m_bWantKeepOpen = FALSE;
  85. }
  86. if ( m_pRequest )
  87. {
  88. // get the bytes....
  89. int nBytes = Receive( m_buf.GetData(), m_buf.GetSize() );
  90. if ( nBytes != SOCKET_ERROR )
  91. {
  92. int ndx = 0;
  93. switch ( m_reqStatus )
  94. {
  95. case REQ_REQUEST:
  96. case REQ_HEADER:
  97. while( GetLine( m_buf, nBytes, ndx ) == TRUE )
  98. {
  99. if ( !m_strLine.IsEmpty() )
  100. ProcessLine();
  101. else
  102. {
  103. m_reqStatus = REQ_BODY;
  104. break;
  105. }
  106. }
  107. // break if we're not looking for the body....
  108. if ( m_reqStatus != REQ_BODY )
  109. break;
  110. // stop if no body sent....
  111. if ( !BodySent() )
  112. {
  113. m_reqStatus = REQ_DONE;
  114. break;
  115. }
  116. // else fall through....
  117. case REQ_BODY:
  118. AddToBody( nBytes, ndx );
  119. break;
  120. }
  121. if ( m_reqStatus == REQ_DONE )
  122. {
  123. m_buf.SetSize(0);
  124. if ( !StartResponse() )
  125. AsyncSelect( FD_WRITE | FD_CLOSE );
  126. }
  127. }
  128. else
  129. nBytes = GetLastError();
  130. }
  131. else
  132. {
  133. // couldn't allocate request object....
  134. ShutDown( both );
  135. m_bKilled = TRUE;
  136. Release();
  137. }
  138. }
  139. void CRequestSocket::OnSend(int nErrorCode)
  140. {
  141. int nBytes = Send( m_buf.GetData(), m_cbOut );
  142. if ( nBytes == SOCKET_ERROR )
  143. {
  144. if ( GetLastError() != WSAEWOULDBLOCK )
  145. {
  146. ShutDown( both );
  147. m_bKilled = TRUE;
  148. Release();
  149. }
  150. else
  151. AsyncSelect( FD_WRITE | FD_CLOSE );
  152. }
  153. else if ( nBytes < m_cbOut )
  154. {
  155. // still got some left....
  156. m_buf.RemoveAt( 0, nBytes );
  157. m_cbOut -= nBytes;
  158. // adjust the bytes-sent value for the request....
  159. m_pRequest->m_cbSent += nBytes;
  160. // set up for next write....
  161. AsyncSelect( FD_WRITE | FD_CLOSE );
  162. }
  163. else
  164. {
  165. // adjust the bytes-sent value for the request....
  166. m_pRequest->m_cbSent += nBytes;
  167. // if we're not done with the file....
  168. if ( m_hFile != INVALID_HANDLE_VALUE )
  169. {
  170. DWORD dwRead = 0;
  171. // read next chunk....
  172. ReadFile( m_hFile, m_buf.GetData(),
  173. m_buf.GetSize(), &dwRead, NULL );
  174. if ( dwRead > 0 )
  175. m_cbOut = dwRead;
  176. else
  177. {
  178. // no more data to send....
  179. CloseHandle( m_hFile );
  180. m_hFile = INVALID_HANDLE_VALUE;
  181. }
  182. }
  183. // see if we need to keep going....
  184. if ( m_hFile != INVALID_HANDLE_VALUE )
  185. AsyncSelect( FD_WRITE | FD_CLOSE );
  186. else
  187. {
  188. // eh, we're outta here....
  189. ShutDown( both );
  190. m_bKilled = TRUE;
  191. Release();
  192. }
  193. }
  194. }
  195. void CRequestSocket::OnClose(int nErrorCode)
  196. {
  197. m_bKilled = TRUE;
  198. Release();
  199. }
  200. BOOL CRequestSocket::GetLine( const CByteArray& bytes, int nBytes, int& ndx )
  201. {
  202. BOOL bLine = FALSE;
  203. while ( bLine == FALSE && ndx < nBytes )
  204. {
  205. char ch = (char)(bytes.GetAt( ndx ));
  206. switch( ch )
  207. {
  208. case 'r': // ignore
  209. break;
  210. case 'n': // end-of-line
  211. bLine = TRUE;
  212. break;
  213. default:   // other....
  214. m_strLine += ch;
  215. break;
  216. }
  217. ++ndx;
  218. }
  219. return bLine;
  220. }
  221. void CRequestSocket::ProcessLine( void )
  222. {
  223. int ndx;
  224. switch( m_reqStatus )
  225. {
  226. case REQ_REQUEST:
  227. ndx = m_strLine.Find( ' ' );
  228. if ( ndx != -1 )
  229. {
  230. m_pRequest->m_strMethod = m_strLine.Left( ndx );
  231. m_strLine = m_strLine.Mid( ndx+1 );
  232. m_strLine.TrimLeft();
  233. ndx = m_strLine.Find( ' ' );
  234. if ( ndx == -1 )
  235. {
  236. m_pRequest->m_strURL = m_strLine;
  237. m_pRequest->m_strURL.TrimRight();
  238. m_reqStatus = REQ_SIMPLE;
  239. }
  240. else
  241. {
  242. m_pRequest->m_strURL = m_strLine.Left( ndx );
  243. m_pRequest->m_strVersion = m_strLine.Mid( ndx+1 );
  244. m_pRequest->m_strVersion.TrimLeft();
  245. }
  246. // check for execution arguments....
  247. ndx = m_pRequest->m_strURL.Find( '?' );
  248. if ( ndx != -1 )
  249. {
  250. // yup; save the args....
  251. m_pRequest->m_strArgs = m_pRequest->m_strURL.Mid( ndx+1 );
  252. // strip from file name....
  253. m_pRequest->m_strURL = m_pRequest->m_strURL.Left( ndx );
  254. m_pRequest->m_dwExecute = CRequest::APP_EXECUTE;
  255. }
  256. // change any "%xx"s to the appropriate char....
  257. m_pRequest->m_strURL = Decode( m_pRequest->m_strURL );
  258. }
  259. m_reqStatus = REQ_HEADER;
  260. break;
  261. case REQ_HEADER:
  262. ndx = m_strLine.Find( ':' );
  263. if ( ndx != -1 )
  264. {
  265. CString strName = m_strLine.Left( ndx );
  266. CString strValue = m_strLine.Mid( ndx+1 );
  267. strName.MakeLower();
  268. strValue.TrimLeft();
  269. m_pRequest->m_mapHeaders.SetAt( strName, strValue );
  270. }
  271. break;
  272. };
  273. m_strLine.Empty();
  274. }
  275. BOOL CRequestSocket::BodySent( void )
  276. {
  277. BOOL bSent = FALSE;
  278. CString strValue = m_pRequest->GetHeaderValue( "Content-Length" );
  279. if ( !strValue.IsEmpty() )
  280. {
  281. m_pRequest->m_cbBody = atoi( strValue );
  282. bSent = TRUE;
  283. }
  284. return bSent;
  285. }
  286. void CRequestSocket::AddToBody( int nBytes, int ndx )
  287. {
  288. // save the buffer size....
  289. int nOldSize = m_buf.GetSize();
  290. // get rid of old stuff; append to body data....
  291. m_buf.RemoveAt( 0, ndx );
  292. m_buf.SetSize( nBytes - ndx );
  293. m_pRequest->m_baBody.Append( m_buf );
  294. // restore the buffer size....
  295. m_buf.SetSize( nOldSize );
  296. // see if we're done....
  297. if ( m_pRequest->m_baBody.GetSize() >= m_pRequest->m_cbBody )
  298. {
  299. m_pRequest->m_baBody.SetSize( m_pRequest->m_cbBody );
  300. m_reqStatus = REQ_DONE;
  301. }
  302. }
  303. BOOL CRequestSocket::StartResponse( void )
  304. {
  305. BOOL bWait = FALSE;
  306. CString strFile;
  307. UINT uPort;
  308. // save the host address....
  309. GetPeerName( m_pRequest->m_strHost, uPort );
  310. // switch on the method....
  311. if ( m_pRequest->m_cbBody == 0 &&
  312. m_pRequest->m_strMethod.CompareNoCase( "GET" ) == 0 )
  313. {
  314. FindTarget( strFile );
  315. if( m_pRequest->m_uStatus == 0 )
  316. {
  317. if ( m_pRequest->m_dwExecute )
  318. bWait=StartSvrApp();
  319. else
  320. {
  321. if ( StuffHeading() )
  322. StartTargetStuff();
  323. }
  324. }
  325. }
  326. else if ( m_pRequest->m_cbBody == 0 && m_reqStatus == REQ_DONE &&
  327. m_pRequest->m_strMethod.CompareNoCase( "HEAD" ) == 0 )
  328. {
  329. FindTarget( strFile );
  330. if( m_pRequest->m_uStatus == 0 )
  331. {
  332. if ( m_pRequest->m_dwExecute )
  333. bWait=StartSvrApp();
  334. else
  335. {
  336. StuffHeading();
  337. // we don't send the file for HEAD reqs....
  338. if ( m_hFile != INVALID_HANDLE_VALUE)
  339. {
  340. CloseHandle( m_hFile );
  341. m_hFile = INVALID_HANDLE_VALUE;
  342. }
  343. }
  344. }
  345. }
  346. else if ( m_pRequest->m_cbBody > 0 && m_reqStatus == REQ_DONE &&
  347. m_pRequest->m_strMethod.CompareNoCase( "POST" ) == 0 )
  348. {
  349. // assume an executable....
  350. m_pRequest->m_dwExecute = CRequest::APP_EXECUTE;
  351. FindTarget( strFile );
  352. if ( m_pRequest->m_uStatus == 0 )
  353. {
  354. bWait=StartSvrApp();
  355. }
  356. }
  357. else
  358. StuffError( IDS_STATUS_NOTIMPL );
  359. // notify the active view of the hit....
  360. m_pDoc->DocHit( m_pRequest );
  361. return bWait;
  362. }
  363. BOOL CRequestSocket::FindTarget( CString& strFile )
  364. {
  365. BOOL bFound = FALSE;
  366. strFile = m_pRequest->m_strURL;
  367. // change from URL to local file system path....
  368. if ( URLtoPath( strFile ) )
  369. {
  370. CString strExtra; // extra path info
  371. m_pRequest->m_dwAttr = GetFileAttributes( strFile );
  372. if ( m_pRequest->m_dwAttr != -1 )
  373. bFound = TRUE;
  374. else
  375. {
  376. // rip off the last portion....
  377. strExtra = StripLast( strFile );
  378. while( !strFile.IsEmpty() )
  379. {
  380. // anything there?
  381. m_pRequest->m_dwAttr = GetFileAttributes( strFile );
  382. if ( m_pRequest->m_dwAttr != -1 )
  383. {
  384. // found something; better not be a folder....
  385. if( (m_pRequest->m_dwAttr&FILE_ATTRIBUTE_DIRECTORY) == 0 )
  386. bFound = TRUE;
  387. break;
  388. }
  389. // rip off the next portion....
  390. strExtra = StripLast( strFile ) + strExtra;
  391. }
  392. }
  393. if ( bFound )
  394. {
  395. // strip any trailing SEPCHAR....
  396. if ( strFile.GetAt( strFile.GetLength()-1) == SEPCHAR )
  397. m_pRequest->m_strFullPath = strFile.Left( strFile.GetLength()-1 );
  398. else
  399. m_pRequest->m_strFullPath = strFile;
  400. // see if we need to set the extra path info....
  401. if ( !strExtra.IsEmpty() )
  402. {
  403. m_pRequest->m_strPathInfo = strExtra;
  404. if ( URLtoPath( strExtra ) )
  405. m_pRequest->m_strPathTranslated = strExtra;
  406. }
  407. // if it's a folder, see if we can redirect to
  408. // on of the default docs or apps....
  409. if ( m_pRequest->m_dwAttr & FILE_ATTRIBUTE_DIRECTORY )
  410. {
  411. // check for existence of a default doc or app....
  412. if ( !CheckDefault( IDS_DEFAULTDOC, FALSE ) )
  413. CheckDefault( IDS_DEFAULTAPP, TRUE );
  414. }
  415. else if ( m_pRequest->m_dwExecute && !IsSvrApp() )
  416. {
  417. StuffError( IDS_STATUS_BADREQUEST );
  418. }
  419. }
  420. else
  421. StuffError( IDS_STATUS_NOTFOUND );
  422. }
  423. else
  424. StuffError( IDS_STATUS_BADREQUEST );
  425. return bFound;
  426. }
  427. BOOL CRequestSocket::URLtoPath( CString& strFile )
  428. {
  429. BOOL bLegal = FALSE;
  430. CString& strRoot = m_pDoc->m_strRoot;
  431. // start with the root, append the abs path....
  432. CString strTemp = strRoot + strFile;
  433. // now canonicalize it....
  434. DWORD dwSize = GetFullPathName( strTemp, MAX_PATH, strFile.GetBuffer(MAX_PATH+1), NULL );
  435. strFile.ReleaseBuffer();
  436. // get the full path okay?
  437. if ( dwSize )
  438. {
  439. int cchRoot = strRoot.GetLength();
  440. int cchFile = strFile.GetLength();
  441. // must be the same or longer than the root....
  442. if ( cchRoot == cchFile )
  443. {
  444. // must be exactly the same....
  445. if ( strRoot.Compare( strFile ) == 0 )
  446. bLegal = TRUE;
  447. }
  448. else if ( cchRoot < cchFile )
  449. {
  450. // must have the root as the base....
  451. if ( strRoot.Compare( strFile.Left(cchRoot) ) == 0
  452. && strFile.GetAt( cchRoot ) == SEPCHAR )
  453. bLegal = TRUE;
  454. }
  455. }
  456. return bLegal;
  457. }
  458. BOOL CRequestSocket::PathToURL( CString& strFile )
  459. {
  460. int ndx;
  461. // a local reference to the root....
  462. CString& strRoot = m_pDoc->m_strRoot;
  463. // change all SEPCHARs to forward slashes....
  464. while ( (ndx=strFile.Find( SEPCHAR )) != -1 )
  465. strFile = strFile.Left( ndx ) + '/' + strFile.Mid(ndx+1);
  466. // now add the prefix and server, and cut the root....
  467. CString strPort;
  468. UINT uPort = m_pDoc->m_uPort;
  469. if ( uPort != PORT_HTTP )
  470. strPort.Format( ":%d", uPort );
  471. strFile = CString("http://")
  472. + m_pDoc->m_strServer
  473. + strPort
  474. + strFile.Mid(strRoot.GetLength());
  475. return TRUE;
  476. }
  477. int CRequestSocket::StuffString( const CString& strData )
  478. {
  479. int nLen = strData.GetLength()*sizeof(TCHAR);
  480. // make sure there's enough room....
  481. if ( m_cbOut + nLen > m_buf.GetSize() )
  482. {
  483. int nChunks = nLen/1024 + 1;
  484. m_buf.SetSize( m_cbOut + nChunks*1024 );
  485. }
  486. // copy the data....
  487. MoveMemory( m_buf.GetData() + m_cbOut, (LPCSTR)strData, nLen );
  488. m_cbOut += nLen;
  489. // return amount of space left....
  490. return (m_buf.GetSize() - m_cbOut);
  491. }
  492. int CRequestSocket::StuffString( UINT uId )
  493. {
  494. CString str;
  495. str.LoadString( uId );
  496. return StuffString( str );
  497. }
  498. int CRequestSocket::StuffStatus( const CString& strStatus )
  499. {
  500. CString strVer = "HTTP/1.0 ";
  501. StuffString( strVer );
  502. StuffString( strStatus );
  503. StuffString( CRLF );
  504. // stuff the server name....
  505. CString strServer;
  506. if ( strServer.LoadString( IDS_SERVER_NAME ) && !strServer.IsEmpty() )
  507. StuffHeader( "Server", strServer );
  508. // stuff the date....
  509. return StuffHeader( "Date", GetHttpDate() );
  510. }
  511. int CRequestSocket::StuffStatus( UINT uStatus )
  512. {
  513. CString strStatus;
  514. strStatus.LoadString( uStatus );
  515. // save the status for this request....
  516. m_pRequest->m_uStatus = uStatus;
  517. // stuff the HTTP status line....
  518. return StuffStatus( strStatus );
  519. }
  520. int CRequestSocket::StuffError( UINT uMsg )
  521. {
  522. StuffStatus( uMsg );
  523. return StuffString( CRLF );
  524. }
  525. int CRequestSocket::StuffHeader( CString strName, CString strValue )
  526. {
  527. StuffString( strName );
  528. StuffString( ": " );
  529. StuffString( strValue );
  530. return StuffString( CRLF );
  531. }
  532. int CRequestSocket::StuffHeader( CString strName, int nValue )
  533. {
  534. CString strValue;
  535. StuffString( strName );
  536. StuffString( ": " );
  537. strValue.Format( "%d", nValue );
  538. StuffString( strValue );
  539. return StuffString( CRLF );
  540. }
  541. BOOL CRequestSocket::StuffHeading( void )
  542. {
  543. BOOL bContinue = FALSE;
  544. if ( m_pRequest->m_dwAttr & FILE_ATTRIBUTE_HIDDEN )
  545. {
  546. // never show hidden files....
  547. StuffError( IDS_STATUS_FORBIDDEN );
  548. }
  549. else if ( m_pRequest->m_dwAttr & FILE_ATTRIBUTE_DIRECTORY )
  550. {
  551. if ( m_pDoc->m_bAllowListing )
  552. {
  553. // create a directory listing....
  554. StuffStatus( IDS_STATUS_OK );
  555. StuffString( CRLF );
  556. bContinue = TRUE;
  557. }
  558. else
  559. StuffError( IDS_STATUS_FORBIDDEN );
  560. }
  561. #ifdef IMPL_CGI
  562. else if ( m_hFile != INVALID_HANDLE_VALUE )
  563. {
  564. // cgi's output file will be opened already....
  565. CString strStatus, strHeaders;
  566. // loop until we find a blank line....
  567. DWORD dwRead = 0;
  568. CByteArray baFile;
  569. baFile.SetSize( 1024 );
  570. // read next chunk....
  571. BOOL bRead = ReadFile( m_hFile, baFile.GetData(),
  572. baFile.GetSize(), &dwRead, NULL );
  573. while ( dwRead > 0 )
  574. {
  575. int ndx = 0;
  576. while( GetLine( baFile, dwRead, ndx ) == TRUE )
  577. {
  578. BOOL bSave = TRUE;
  579. // stuff any non-empty lines.....
  580. if ( m_strLine.IsEmpty() )
  581. {
  582. // we found our empty line;
  583. // back up to where we left off....
  584. DWORD dwPos = SetFilePointer( m_hFile,
  585. ndx - dwRead,
  586. NULL, FILE_CURRENT );
  587. // and we're off....
  588. bContinue = TRUE;
  589. break;
  590. }
  591. else
  592. {
  593. int nPos = m_strLine.Find( ':' );
  594. if ( nPos != -1 )
  595. {
  596. CString strName = m_strLine.Left( nPos );
  597. strName.TrimLeft();
  598. strName.TrimRight();
  599. CString strVal  = m_strLine.Mid( nPos+1 );
  600. strVal.TrimLeft();
  601. strVal.TrimRight();
  602. if ( strName.CompareNoCase("Status") == 0 )
  603. {
  604. strStatus = strVal;
  605. bSave = FALSE;
  606. }
  607. else if ( strName.CompareNoCase("Location") == 0 )
  608. {
  609. strStatus.LoadString( IDS_STATUS_MOVEDTEMP );
  610. }
  611. }
  612. }
  613. // save the header (if we want to)....
  614. if ( bSave )
  615. strHeaders += m_strLine + CRLF;
  616. m_strLine.Empty();
  617. }
  618. // read next chunk if we're not done....
  619. if ( bContinue )
  620. break;
  621. else
  622. ReadFile( m_hFile, baFile.GetData(),
  623. baFile.GetSize(), &dwRead, NULL );
  624. }
  625. if ( strStatus.IsEmpty() )
  626. StuffStatus( IDS_STATUS_OK );
  627. else
  628. StuffStatus( strStatus );
  629. // stuff the headers....
  630. StuffString( strHeaders );
  631. // stuff the blank line....
  632. StuffString( CRLF );
  633. }
  634. #endif // IMPL_CGI
  635. else
  636. {
  637. // open the file....
  638. m_hFile = CreateFile( m_pRequest->m_strFullPath,
  639. GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
  640. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
  641. NULL );
  642. if ( m_hFile != INVALID_HANDLE_VALUE )
  643. {
  644. if ( m_reqStatus != REQ_SIMPLE )
  645. {
  646. CTime timeIfMod;
  647. CString strIfMod = m_pRequest->GetHeaderValue( "If-Modified-Since" );
  648. if ( strIfMod.GetLength() > 0 &&
  649. FromHttpTime( strIfMod, timeIfMod ) &&
  650. !IfModSince( timeIfMod ) )
  651. {
  652. // eh, it hasn't been modified....
  653. StuffStatus( IDS_STATUS_NOTMODIFIED );
  654. // don't need it anymore....
  655. CloseHandle( m_hFile );
  656. m_hFile = INVALID_HANDLE_VALUE;
  657. }
  658. else
  659. {
  660. // send it off....
  661. StuffStatus( IDS_STATUS_OK );
  662. // any other header info....
  663. StuffFileType();
  664. StuffHeader( "Content-length", GetFileSize( m_hFile, NULL ) );
  665. // get the last modified time....
  666. FILETIME ft;
  667. if ( GetFileTime( m_hFile, NULL, NULL, &ft ) )
  668. {
  669. StuffHeader( "Last-Modified", GetHttpDate( &ft ) );
  670. }
  671. bContinue = TRUE;
  672. }
  673. // blank line....
  674. StuffString( CRLF );
  675. }
  676. else
  677. bContinue = TRUE;
  678. }
  679. else
  680. {
  681. // couldn't open; try again later....
  682. StuffError( IDS_STATUS_SVCUNAVAIL );
  683. }
  684. }
  685. return bContinue;
  686. }
  687. void CRequestSocket::StartTargetStuff( void )
  688. {
  689. if ( m_hFile != INVALID_HANDLE_VALUE)
  690. {
  691. DWORD dwRead = 0;
  692. // read the first chunk....
  693. ReadFile( m_hFile, m_buf.GetData() + m_cbOut,
  694. m_buf.GetSize()-m_cbOut, &dwRead, NULL );
  695. if ( dwRead > 0 )
  696. m_cbOut += dwRead;
  697. else
  698. {
  699. // nothing read.... close the file....
  700. CloseHandle( m_hFile );
  701. m_hFile = INVALID_HANDLE_VALUE;
  702. }
  703. }
  704. else if ( m_pRequest->m_dwAttr & FILE_ATTRIBUTE_DIRECTORY )
  705. StuffListing();
  706. else
  707. StuffString( CRLF );
  708. }
  709. void CRequestSocket::StuffListing( void )
  710. {
  711. BOOL bRoot = FALSE;
  712. BOOL bIcons = m_pDoc->m_bListIcon;
  713. CString strIcon;
  714. CString strLine = CString("http://")
  715. + m_pDoc->m_strServer
  716. + m_pRequest->m_strURL;
  717. CString strDir = m_pRequest->m_strURL;
  718. CString strMask = m_pRequest->m_strFullPath;
  719. // make sure URL ends in a slash....
  720. if ( strDir.GetAt( strDir.GetLength()-1 ) != '/' )
  721. strDir += '/';
  722. // is this the server's root folder?
  723. else if ( strDir.Compare( "/" ) == 0 )
  724. bRoot = TRUE;
  725. // create the file search mask....
  726. AddFile( strMask, IDS_DIRMASK );
  727. StuffString( IDS_CONTENTS_PRE );
  728. StuffString( strLine );
  729. StuffString( IDS_CONTENTS_POST );
  730. if ( bRoot )
  731. StuffString( IDS_CONTENTS_DESC );
  732. if ( bIcons )
  733. strIcon.LoadString( IDS_ICON_BLANK );
  734. strLine.Format( IDS_CONTENTS_HEADING, strIcon );
  735. StuffString( strLine );
  736. int nFiles = 0;
  737. WIN32_FIND_DATA fd;
  738. // find the first file that matches the mask....
  739. HANDLE fh = FindFirstFile( strMask, &fd );
  740. if ( fh != INVALID_HANDLE_VALUE )
  741. {
  742. // create a line for the found file....
  743. nFiles += StuffListingFile( &fd, strDir, bIcons );
  744. // loop through all other files....
  745. while ( FindNextFile( fh, &fd ) )
  746. nFiles += StuffListingFile( &fd, strDir, bIcons );
  747. }
  748. if ( nFiles == 0 )
  749. StuffString( IDS_CONTENTS_EMPTY );
  750. StuffString( IDS_CONTENTS_FOOTER );
  751. // only add the parent link if there is one....
  752. if ( !bRoot )
  753. {
  754. if ( bIcons )
  755. strIcon.LoadString( IDS_ICON_PARENT );
  756. strLine.Format( IDS_CONTENTS_PARENT, strIcon );
  757. StuffString( strLine );
  758. }
  759. // add the note and end it....
  760. StuffString( IDS_CONTENTS_NOTE );
  761. StuffString( CRLF );
  762. }
  763. int CRequestSocket::StuffListingFile( WIN32_FIND_DATA* pfd, const CString& strDir, BOOL bIcons )
  764. {
  765. int nFile = 0;
  766. // don't include '.', '..' or hidden files....
  767. if ( lstrcmp( pfd->cFileName, "." ) && lstrcmp( pfd->cFileName, ".." )
  768. && (pfd->dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) == 0 )
  769. {
  770. CString strSize, strIcon = "";
  771. CString strLine, strFile = pfd->cFileName;
  772. CTime timeFile( pfd->ftLastWriteTime );
  773. BOOL bFolder = ((pfd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0);
  774. if ( bIcons && bFolder )
  775. strIcon.LoadString( IDS_ICON_FOLDER );
  776. else if ( bIcons )
  777. strIcon.LoadString( IDS_ICON_FILE );
  778. // create the link string....
  779. CString strLink = strDir + strFile;
  780. // make sure spaces are replaced with '%20'...
  781. int ndx;
  782. while ( (ndx=strLink.Find(' ')) != -1 )
  783. strLink = strLink.Left(ndx) + "%20" + strLink.Mid( ndx+1 );
  784. // format the size string....
  785. if ( bFolder )
  786. strSize = "  Folder";
  787. else if ( pfd->nFileSizeHigh > 0 )
  788. strSize = "   &gt; 4GB"; // yeah, right.
  789. else if ( pfd->nFileSizeLow < 1024 )
  790. strSize = "    &lt; 1K";
  791. else
  792. strSize.Format( "%7dK", pfd->nFileSizeLow/1024 );
  793. strLine.Format( IDS_CONTENTS_FORMAT,
  794. timeFile.Format( IDS_FILETIMEFMT ),
  795. strSize, strLink, strIcon, strFile );
  796. StuffString( strLine );
  797. nFile = 1;
  798. }
  799. return nFile;
  800. }
  801. BOOL CRequestSocket::StartSvrApp( void )
  802. {
  803. #ifdef IMPL_CGI
  804. if ( m_pRequest->m_dwExecute != CRequest::APP_ISAPI )
  805. return CGIStart();
  806. else
  807. {
  808. StuffError( IDS_STATUS_NOTIMPL );
  809. return FALSE;
  810. }
  811. #else //  IMPL_CGI
  812. StuffError( IDS_STATUS_NOTIMPL );
  813. return FALSE;
  814. #endif // IMPL_CGI
  815. }
  816. #ifdef IMPL_CGI
  817. BOOL CRequestSocket::CGIStart( void )
  818. {
  819. BOOL bOk = FALSE;
  820. // get the temp path...
  821. CString strTempPath;
  822. GetTempPath( MAX_PATH, strTempPath.GetBuffer(MAX_PATH) );
  823. strTempPath.ReleaseBuffer();
  824. // create a temporary file for the output....
  825. CString strTempName;
  826. GetTempFileName( strTempPath, "CGI", 0, strTempName.GetBuffer(MAX_PATH) );
  827. strTempName.ReleaseBuffer();
  828. m_hFile = CreateFile( strTempName, GENERIC_READ|GENERIC_WRITE,
  829. FILE_SHARE_READ|FILE_SHARE_WRITE, &g_sa,
  830. CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY|FILE_FLAG_DELETE_ON_CLOSE, NULL );
  831. if ( m_hFile != INVALID_HANDLE_VALUE )
  832. {
  833. // create the cancel event....
  834. m_pCancel = new CEvent;
  835. if ( m_pCancel )
  836. {
  837. // make sure the event is reset....
  838. m_pCancel->ResetEvent();
  839. // create the CGI thread suspended....
  840. m_pThread = AfxBeginThread( (AFX_THREADPROC)CGIThread,
  841. (LPVOID)this, THREAD_PRIORITY_NORMAL, 0,
  842. CREATE_SUSPENDED, NULL );
  843. if ( m_pThread )
  844. {
  845. // don't self-destruct (we must delete)....
  846. m_pThread->m_bAutoDelete = FALSE;
  847. // resume...
  848. m_pThread->ResumeThread();
  849. bOk = TRUE;
  850. }
  851. }
  852. }
  853. if ( bOk == FALSE )
  854. {
  855. StuffError( IDS_STATUS_SVRERROR );
  856. if( m_hFile != INVALID_HANDLE_VALUE )
  857. { // JIC....
  858. CloseHandle( m_hFile );
  859. m_hFile = INVALID_HANDLE_VALUE;
  860. }
  861. }
  862. return bOk;
  863. }
  864. void AddEnvVar( CString& strEnv, CString strName, CString strVal )
  865. {
  866. // add the name=val pair to the env in alphabetical order....
  867. strEnv += strName + '=' + strVal + 'a';
  868. }
  869. UINT CGIThread( LPVOID pvParam )
  870. {
  871. CRequestSocket* pReqSock = (CRequestSocket*)pvParam;
  872. CRequest* pRequest = pReqSock->m_pRequest;
  873. BOOL bOk = FALSE;
  874. DWORD dwErr;
  875. HANDLE hWritePipe, hReadPipe;
  876. // create a pipe we'll use for STDIN....
  877. if ( CreatePipe( &hReadPipe, &hWritePipe, &g_sa, 0 ) )
  878. {
  879. // get the command line together....
  880. CString strCmdLine = pRequest->m_strFullPath
  881. + ' '
  882. + Decode( pRequest->m_strArgs, TRUE );
  883. // get the directory....
  884. CString strDir = pRequest->m_strFullPath;
  885. int ndx = strDir.ReverseFind( SEPCHAR );
  886. // assume we found it....
  887. strDir = strDir.Left( ndx+1 );
  888. // create an environment for the CGI process....
  889. DWORD dwCreateFlags = 0;
  890. #ifdef UNICODE
  891. dwCreateFlags = CREATE_UNICODE_ENVIRONMENT;
  892. #endif // UNICODE
  893. CEnvironment cEnv;
  894. CString strValue;
  895. strValue.LoadString( IDS_SERVER_NAME );
  896. cEnv.Add( "SERVER_SOFTWARE", strValue );
  897. cEnv.Add( "SERVER_NAME", pReqSock->m_pDoc->m_strServer );
  898. cEnv.Add( "GATEWAY_INTERFACE", "CGI/1.1" );
  899. cEnv.Add( "SERVER_PROTOCOL", "HTTP/1.0" );
  900. strValue.Format( "%d", pReqSock->m_pDoc->m_uPort );
  901. cEnv.Add( "SERVER_PORT", strValue );
  902. cEnv.Add( "REQUEST_METHOD", pRequest->m_strMethod );
  903. cEnv.Add( "SCRIPT_NAME", pRequest->m_strURL );
  904. cEnv.Add( "QUERY_STRING", pRequest->m_strArgs );
  905. cEnv.Add( "REMOTE_ADDR", pRequest->m_strHost );
  906. if ( pRequest->m_cbBody > 0 )
  907. {
  908. cEnv.Add( "CONTENT_LENGTH", pRequest->GetHeaderValue("Content-Length") );
  909. cEnv.Add( "CONTENT_TYPE", pRequest->GetHeaderValue("Content-Type") );
  910. }
  911. if ( !pRequest->m_strPathInfo.IsEmpty() )
  912. {
  913. cEnv.Add( "PATH_INFO", pRequest->m_strPathInfo );
  914. cEnv.Add( "PATH_TRANSLATED", pRequest->m_strPathTranslated );
  915. }
  916. // all the passed headers prefixed with "HTTP_"....
  917. POSITION pos = pRequest->m_mapHeaders.GetStartPosition();
  918. while ( pos != NULL )
  919. {
  920. // get the name/value pair....
  921. CString strName, strValue;
  922. pRequest->m_mapHeaders.GetNextAssoc( pos, strName, strValue );
  923. HeaderToEnvVar( strName );
  924. // set the environment variable....
  925. cEnv.Add( strName, strValue );
  926. }
  927. // create the process....
  928. LPVOID pEnv = (LPVOID)cEnv.GetBlock();
  929. PROCESS_INFORMATION pi;
  930. STARTUPINFO si = {0};
  931. si.cb = sizeof(si);
  932. si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
  933. si.wShowWindow = SW_HIDE;
  934. si.hStdInput = hReadPipe;
  935. si.hStdOutput = pReqSock->m_hFile;
  936. si.hStdError = pReqSock->m_hFile;
  937. bOk = CreateProcess( NULL, strCmdLine.GetBuffer(1),
  938. NULL, NULL, TRUE,
  939. dwCreateFlags, pEnv,
  940. strDir, &si, &pi );
  941. strCmdLine.ReleaseBuffer();
  942. // if created....
  943. if ( bOk )
  944. {
  945. // release our hold on the thread....
  946. CloseHandle( pi.hThread );
  947. // send the body of the post to the stdin....
  948. if ( pRequest->m_cbBody > 0 )
  949. {
  950. DWORD dwWritten = 0;
  951. WriteFile( hWritePipe, pRequest->m_baBody.GetData(),
  952. pRequest->m_cbBody, &dwWritten, NULL );
  953. }
  954. // wait for either cancel or process done....
  955. HANDLE aHandles[2];
  956. aHandles[0] = pi.hProcess;
  957. aHandles[1] = pReqSock->m_pCancel->m_hObject;
  958. if ( WaitForMultipleObjects( 2, aHandles, FALSE, INFINITE ) == WAIT_OBJECT_0 )
  959. {
  960. // process finished; notify main thread....
  961. AfxGetApp()->m_pMainWnd->PostMessage( WSM_CGIDONE, 0, (LPARAM)pReqSock );
  962. }
  963. else
  964. {
  965. // canceled or some other error....
  966. bOk = FALSE;
  967. }
  968. // close our hold on it....
  969. CloseHandle( pi.hProcess );
  970. }
  971. else
  972. dwErr = GetLastError();
  973. // close the stdin pipe....
  974. CloseHandle( hWritePipe );
  975. CloseHandle( hReadPipe );
  976. delete pEnv;
  977. }
  978. if ( bOk == FALSE && pReqSock->m_hFile != INVALID_HANDLE_VALUE )
  979. { // JIC....
  980. CloseHandle( pReqSock->m_hFile );
  981. pReqSock->m_hFile = INVALID_HANDLE_VALUE;
  982. }
  983. return (bOk?0:1);
  984. }
  985. void CRequestSocket::CGIDone( void )
  986. {
  987. if ( !m_bKilled )
  988. {
  989. // flush the temp file's buffers....
  990. BOOL bSucceed = FlushFileBuffers( m_hFile );
  991. // go to start of file....
  992. DWORD dwPos = SetFilePointer( m_hFile, 0, NULL, FILE_BEGIN );
  993. // output the header....
  994. StuffHeading();
  995. if ( m_pRequest->m_strMethod.Compare( "HEAD" ) )
  996. StartTargetStuff();
  997. else
  998. {
  999. CloseHandle( m_hFile );
  1000. m_hFile = INVALID_HANDLE_VALUE;
  1001. }
  1002. AsyncSelect( FD_WRITE | FD_CLOSE );
  1003. }
  1004. else
  1005. {
  1006. CloseHandle( m_hFile );
  1007. m_hFile = INVALID_HANDLE_VALUE;
  1008. }
  1009. }
  1010. void HeaderToEnvVar( CString& strVar )
  1011. {
  1012. int ndx;
  1013. // make upper case, change '-' to '_', and prefix....
  1014. strVar.MakeUpper();
  1015. while( (ndx = strVar.Find('-')) != -1 )
  1016. strVar = strVar.Left(ndx) + '_' + strVar.Mid(ndx+1);
  1017. strVar = "HTTP_" + strVar;
  1018. }
  1019. CEnvironment::CEnvironment( void )
  1020. {
  1021. m_nSize = 2;
  1022. }
  1023. CEnvironment::~CEnvironment( void )
  1024. {
  1025. }
  1026. BOOL CEnvironment::Add( CString name, CString value )
  1027. {
  1028. BOOL bOk = TRUE;
  1029. // create the entry pair string....
  1030. CString strPair = name + __TEXT('=') + value;
  1031. m_nSize += strPair.GetLength() + 1;
  1032. POSITION pos = m_list.GetHeadPosition();
  1033. // find the first item bigger than this string....
  1034. while( pos != NULL )
  1035. {
  1036. if ( m_list.GetAt(pos).CompareNoCase(strPair) > 0 )
  1037. {
  1038. m_list.InsertBefore( pos, strPair );
  1039. break;
  1040. }
  1041. m_list.GetNext( pos );
  1042. }
  1043. if ( pos == NULL )
  1044. m_list.AddTail( strPair );
  1045. return bOk;
  1046. }
  1047. LPVOID CEnvironment::GetBlock( void )
  1048. {
  1049. // allocate a block....
  1050. PTCHAR pBlock = new TCHAR[m_nSize];
  1051. if ( pBlock )
  1052. {
  1053. // iterate through the list....
  1054. PTCHAR pPos = pBlock;
  1055. POSITION pos = m_list.GetHeadPosition();
  1056. while( pos != NULL )
  1057. {
  1058. CString& str = m_list.GetNext( pos );
  1059. // copy the string....
  1060. lstrcpy( pPos, str );
  1061. pPos += str.GetLength() + 1;
  1062. }
  1063. // NULL for the whole list....
  1064. *pPos = __TEXT('');
  1065. }
  1066. return pBlock;
  1067. }
  1068. #endif // IMPL_CGI
  1069. CString CRequestSocket::GetHttpDate( LPFILETIME pft )
  1070. {
  1071. SYSTEMTIME st;
  1072. if ( pft )
  1073. FileTimeToSystemTime( pft, &st );
  1074. else
  1075. GetSystemTime( &st );
  1076. CTime timeHttp( st );
  1077. return timeHttp.Format( IDS_HTTPTIME );
  1078. }
  1079. BOOL CRequestSocket::IfModSince( const CTime& timeIfMod )
  1080. {
  1081. // assume it has been modified....
  1082. BOOL bOk = TRUE;
  1083. FILETIME ft;
  1084. if ( GetFileTime( m_hFile, NULL, NULL, &ft ) )
  1085. {
  1086. SYSTEMTIME st;
  1087. if ( FileTimeToSystemTime( &ft, &st ) )
  1088. {
  1089. CTime timeFile( st );
  1090. if ( timeFile <= timeIfMod )
  1091. bOk = FALSE;
  1092. }
  1093. }
  1094. return bOk;
  1095. }
  1096. static int IntVal( CString strVal )
  1097. {
  1098. int nVal = 0;
  1099. strVal.TrimLeft();
  1100. for( int ndx = 0; ndx < strVal.GetLength(); ++ndx )
  1101. nVal = nVal*10 + strVal.GetAt(ndx) - '0';
  1102. return nVal;
  1103. }
  1104. static int MonthFromStr( const CString& str )
  1105. {
  1106. LPSTR aMonths[] = {
  1107. "xxx", "jan", "feb", "mar", "apr", "may", "jun",
  1108. "jul", "aug", "sep", "oct", "nov", "dec" };
  1109. for( int nMonth=1; nMonth <= 12; ++nMonth )
  1110. {
  1111. if ( str.CompareNoCase( aMonths[nMonth] ) == 0 )
  1112. break;
  1113. }
  1114. return nMonth;
  1115. }
  1116. // Dow, dd Mon year hh:mm:ss GMT
  1117. BOOL CRequestSocket::FromHttpTime( const CString& strHttp, CTime& timeHttp )
  1118. {
  1119. // assume we couldn't get a good time conversion....
  1120. BOOL bOk = FALSE;
  1121. SYSTEMTIME st = {0};
  1122. int ndx;
  1123. switch( strHttp.GetAt(3) )
  1124. {
  1125. case ',':
  1126. // read RFC-1123 (preferred)....
  1127. st.wDay = IntVal( strHttp.Mid(5,2) );
  1128. st.wMonth = MonthFromStr( strHttp.Mid(8,3) );
  1129. st.wYear = IntVal( strHttp.Mid(12,4) );
  1130. st.wHour = IntVal( strHttp.Mid(17,2) );
  1131. st.wMinute = IntVal( strHttp.Mid(20,2) );
  1132. st.wSecond = IntVal( strHttp.Mid(23,2) );
  1133. break;
  1134. case ' ':
  1135. // read ANSI-C time format....
  1136. st.wDay = IntVal( strHttp.Mid(8,2) );
  1137. st.wMonth = MonthFromStr( strHttp.Mid(4,3) );
  1138. st.wYear = IntVal( strHttp.Mid(20,4) );
  1139. st.wHour = IntVal( strHttp.Mid(11,2) );
  1140. st.wMinute = IntVal( strHttp.Mid(14,2) );
  1141. st.wSecond = IntVal( strHttp.Mid(17,2) );
  1142. break;
  1143. default:
  1144. if ( (ndx = strHttp.Find( ", " )) != -1 )
  1145. {
  1146. st.wDay = IntVal( strHttp.Mid(ndx+2,2) );
  1147. st.wMonth = MonthFromStr( strHttp.Mid(ndx+5,3) );
  1148. st.wYear = IntVal( strHttp.Mid(ndx+9,2) );
  1149. st.wHour = IntVal( strHttp.Mid(ndx+12,2) );
  1150. st.wMinute = IntVal( strHttp.Mid(ndx+15,2) );
  1151. st.wSecond = IntVal( strHttp.Mid(ndx+18,2) );
  1152. // add the correct century....
  1153. st.wYear += (st.wYear > 50)?1900:2000;
  1154. }
  1155. break;
  1156. }
  1157. // if year not zero, we pulled the info out of the string....
  1158. if ( st.wYear != 0 )
  1159. {
  1160. // assume GMT....
  1161. CTime strTime( st );
  1162. // check to see if the minutes are the same....
  1163. if ( strTime.GetMinute() == st.wMinute )
  1164. {
  1165. // assume it worked....
  1166. timeHttp = strTime;
  1167. bOk = TRUE;
  1168. }
  1169. }
  1170. return bOk;
  1171. }
  1172. int CRequestSocket::AddRef( void )
  1173. {
  1174. return ++m_nRefs;
  1175. }
  1176. int CRequestSocket::Release( void )
  1177. {
  1178. int nRefs = --m_nRefs;
  1179. if ( nRefs == 0 )
  1180. delete this;
  1181. return nRefs;
  1182. }
  1183. void CRequestSocket::StuffFileType( void )
  1184. {
  1185. // get the extension....
  1186. CString strExt = m_pRequest->m_strFullPath.Mid(
  1187. m_pRequest->m_strFullPath.ReverseFind('.') );
  1188. // find it in the registry....
  1189. HKEY hKey = NULL;
  1190. if ( RegOpenKeyEx( HKEY_CLASSES_ROOT, strExt,
  1191. 0, KEY_READ, &hKey ) == ERROR_SUCCESS )
  1192. {
  1193. DWORD dwSize = 0;
  1194. // see how long the data is....
  1195. if ( RegQueryValueEx( hKey, "Content Type", NULL, NULL,
  1196. NULL, &dwSize ) == ERROR_SUCCESS )
  1197. {
  1198. CString strType;
  1199. LONG lRet = RegQueryValueEx( hKey, "Content Type", NULL, NULL,
  1200. (LPBYTE)strType.GetBuffer( dwSize ), &dwSize );
  1201. strType.ReleaseBuffer();
  1202. if ( lRet == ERROR_SUCCESS )
  1203. StuffHeader( "Content-type", strType );
  1204. }
  1205. RegCloseKey( hKey );
  1206. }
  1207. }
  1208. CString Decode( const CString& str, BOOL bQuery )
  1209. {
  1210. int ndx;
  1211. CString strDecoded = str;
  1212. // special processing or query strings....
  1213. if ( bQuery )
  1214. {
  1215. // change all '+' to ' '....
  1216. while( (ndx=strDecoded.Find('+')) != -1 )
  1217. strDecoded = strDecoded.Left(ndx) + ' ' + strDecoded.Mid(ndx+1);
  1218. }
  1219. // first see if there are any %s to decode....
  1220. if ( strDecoded.Find( '%' ) != -1 )
  1221. {
  1222. // iterate through the string, changing %dd to special char....
  1223. for( ndx=0; ndx < strDecoded.GetLength(); ndx++ )
  1224. {
  1225. char ch = strDecoded.GetAt( ndx );
  1226. if ( ch == '%' )
  1227. {
  1228. if ( strDecoded.GetAt( ndx+1 ) == '%' )
  1229. {
  1230. // wanna keep one percent sign....
  1231. strDecoded = strDecoded.Left(ndx) + strDecoded.Mid(ndx+1);
  1232. }
  1233. else
  1234. {
  1235. // assume we have a hex value....
  1236. char ch1 = strDecoded.GetAt(ndx+1);
  1237. char ch2 = strDecoded.GetAt(ndx+2);
  1238. ch1 = ch1 >= 'A' ? (ch1&0xdf)-'A' : ch1-'0';
  1239. ch2 = ch2 >= 'A' ? (ch2&0xdf)-'A' : ch2-'0';
  1240. // replace the escape sequence with the char....
  1241. strDecoded = strDecoded.Left(ndx)
  1242. + (char)(ch1*16 + ch2)
  1243. + strDecoded.Mid( ndx+3 );
  1244. }
  1245. }
  1246. }
  1247. }
  1248. return strDecoded;
  1249. }
  1250. CString CRequestSocket::StripLast( CString& strPath )
  1251. {
  1252. CString strExtra;
  1253. if ( !strPath.IsEmpty() )
  1254. {
  1255. int ndx = strPath.ReverseFind( SEPCHAR );
  1256. if ( ndx < 0 )
  1257. ndx = 0;
  1258. strExtra = strPath.Mid( ndx );
  1259. strPath = strPath.Left( ndx );
  1260. }
  1261. return strExtra;
  1262. }
  1263. BOOL CRequestSocket::CheckDefault( UINT uList, BOOL bExecute )
  1264. {
  1265. BOOL bFound = FALSE;
  1266. DWORD dwAttr;
  1267. CString strDefault, strDefList;
  1268. strDefList.LoadString( uList );
  1269. while ( !strDefList.IsEmpty() )
  1270. {
  1271. int ndx;
  1272. strDefault = m_pRequest->m_strFullPath;
  1273. if ( (ndx=strDefList.Find('n')) == -1 )
  1274. {
  1275. AddFile( strDefault, strDefList );
  1276. strDefList.Empty();
  1277. }
  1278. else
  1279. {
  1280. AddFile( strDefault, strDefList.Left(ndx) );
  1281. strDefList = strDefList.Mid( ndx+1 );
  1282. }
  1283. if ( (dwAttr=GetFileAttributes(strDefault)) != -1 &&
  1284. (dwAttr & FILE_ATTRIBUTE_DIRECTORY) == 0 )
  1285. {
  1286. bFound = TRUE;
  1287. break;
  1288. }
  1289. }
  1290. if ( bFound )
  1291. {
  1292. // redirect to the default file....
  1293. PathToURL( strDefault );
  1294. if ( bExecute )
  1295. strDefault += '?';
  1296. StuffStatus( IDS_STATUS_MOVEDTEMP );
  1297. StuffHeader( "Location", strDefault );
  1298. StuffString( CRLF );
  1299. }
  1300. return bFound;
  1301. }
  1302. BOOL CRequestSocket::IsSvrApp( void )
  1303. {
  1304. BOOL bOk = FALSE;
  1305. int ndx = m_pRequest->m_strFullPath.ReverseFind( '.' );
  1306. if ( ndx != -1 )
  1307. {
  1308. CString strExt = m_pRequest->m_strFullPath.Mid( ndx+1 );
  1309. CString strAvail;
  1310. // check if CGI app....
  1311. strAvail.LoadString( IDS_APP_CGI );
  1312. bOk = CheckExt( strExt, strAvail, CRequest::APP_CGI );
  1313. if ( !bOk )
  1314. {
  1315. strAvail.LoadString( IDS_APP_ISAPI );
  1316. bOk = CheckExt( strExt, strAvail, CRequest::APP_ISAPI );
  1317. }
  1318. }
  1319. return bOk;
  1320. }
  1321. BOOL CRequestSocket::CheckExt( const CString& strExt, CString& strAvail, DWORD dwType )
  1322. {
  1323. BOOL bMatch = FALSE;
  1324. CString strPossible;
  1325. // loop through all possible exts....
  1326. while( !strAvail.IsEmpty() )
  1327. {
  1328. int ndx = strAvail.ReverseFind('n');
  1329. if ( ndx == -1 )
  1330. {
  1331. strPossible = strAvail;
  1332. strAvail.Empty();
  1333. }
  1334. else
  1335. {
  1336. strPossible = strAvail.Mid( ndx+1 );
  1337. strAvail = strAvail.Left( ndx );
  1338. }
  1339. if ( strExt.CompareNoCase( strPossible ) == 0 )
  1340. {
  1341. m_pRequest->m_dwExecute = dwType;
  1342. bMatch = TRUE;
  1343. break;
  1344. }
  1345. }
  1346. return bMatch;
  1347. }