Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1121 lines
29 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. httptime.cxx
  5. Abstract:
  6. This file contains routines to get various timestamps from an http response
  7. header.
  8. We handle only the three standards-mandated date forms, since these are used by
  9. the vast majority of sites out there on the WWW. Handling additional date forms
  10. adds to the overhead of these functions, so unless a new form makes headway, we
  11. will keep these functions simple.
  12. Contents:
  13. FGetHttpExpiryTime
  14. FGetHttpLastModifiedTime
  15. FParseHttpDate
  16. FHttpDateTimeToFiletime
  17. FFileTimetoHttpDateTime
  18. HttpDateToSystemTime
  19. HttpTimeFromSystemTime
  20. (FInternalParseHttpDate)
  21. (MapDayMonthToDword)
  22. Author:
  23. Shishir Pardikar (shishirp) 06-Jan-1996
  24. Revision History:
  25. 06-Jan-1996 rfirth
  26. Created this header
  27. 12-Dec-1997 arthurbi
  28. Rewrote the date parser to reduce allocs, and other bad stuff.
  29. --*/
  30. #include <wininetp.h>
  31. #include "httpp.h"
  32. #include "httptime.h"
  33. //
  34. // external prototypes
  35. //
  36. /********************* Local data *******************************************/
  37. /******************** HTTP date format strings ******************************/
  38. // Month
  39. static const char cszJan[]="Jan";
  40. static const char cszFeb[]="Feb";
  41. static const char cszMar[]="Mar";
  42. static const char cszApr[]="Apr";
  43. static const char cszMay[]="May";
  44. static const char cszJun[]="Jun";
  45. static const char cszJul[]="Jul";
  46. static const char cszAug[]="Aug";
  47. static const char cszSep[]="Sep";
  48. static const char cszOct[]="Oct";
  49. static const char cszNov[]="Nov";
  50. static const char cszDec[]="Dec";
  51. // DayOfWeek in rfc1123 or asctime format
  52. static const char cszSun[]="Sun";
  53. static const char cszMon[]="Mon";
  54. static const char cszTue[]="Tue";
  55. static const char cszWed[]="Wed";
  56. static const char cszThu[]="Thu";
  57. static const char cszFri[]="Fri";
  58. static const char cszSat[]="Sat";
  59. // List of weekdays for rfc1123 or asctime style date
  60. static const char *rgszWkDay[7] =
  61. {
  62. cszSun,cszMon,cszTue,cszWed,cszThu,cszFri,cszSat
  63. };
  64. // list of month strings for all date formats
  65. static const char *rgszMon[12] =
  66. {
  67. cszJan,cszFeb,cszMar,cszApr,cszMay,cszJun,
  68. cszJul,cszAug,cszSep,cszOct,cszNov,cszDec
  69. };
  70. /******************** HTTP date format strings ******************************/
  71. /* Http date format: Sat, 29 Oct 1994 19:43:00 GMT */
  72. const char cszHttpDateFmt[]="%s, %02i %s %02i %02i:%02i:%02i GMT";
  73. /****************************************************************************/
  74. /******************************** Local Functions ***************************/
  75. BOOL
  76. FHttpDateTimeToFiletime(
  77. LPCSTR pcszStr, // input datetime string
  78. LPCSTR *rgszWkDay, // day of week strings
  79. LPCSTR *rgszMon, // month strings
  80. LPCSTR pcszSep, // seperators
  81. UINT dateId, // date format
  82. FILETIME *lpft // output filetime in GMT
  83. );
  84. BOOL
  85. FInternalParseHttpDate(
  86. OUT FILETIME *lpft,
  87. OUT SYSTEMTIME *lpSysTime,
  88. IN LPCSTR lpInputBuffer
  89. );
  90. /****************************************************************************/
  91. //+---------------------------------------------------------------------------
  92. //
  93. // Function: FGetHttpExpiryTime
  94. //
  95. // Synopsis:
  96. //
  97. // Arguments:
  98. //
  99. //
  100. // Returns: TRUE if successful. lpft contains the datetime in FILETIME format
  101. //
  102. //
  103. // Notes:
  104. //
  105. //
  106. //----------------------------------------------------------------------------
  107. BOOL FGetHttpExpiryTime(HINTERNET hRequest, FILETIME *lpFt)
  108. {
  109. BOOL fRet=FALSE;
  110. char buff[256];
  111. DWORD dwBuffLen;
  112. dwBuffLen = sizeof(buff);
  113. if (HttpQueryInfo(hRequest, HTTP_QUERY_EXPIRES, NULL, buff, &dwBuffLen, NULL))
  114. {
  115. fRet = FParseHttpDate(lpFt, buff);
  116. }
  117. return fRet;
  118. }
  119. //+---------------------------------------------------------------------------
  120. //
  121. // Function: FGetHttpLastModifiedTime
  122. //
  123. // Synopsis:
  124. //
  125. // Arguments:
  126. //
  127. //
  128. // Returns: TRUE if successful. lpft contains the datetime in FILETIME format
  129. //
  130. //
  131. // Notes:
  132. //
  133. //
  134. //----------------------------------------------------------------------------
  135. BOOL FGetHttpLastModifiedTime(HINTERNET hRequest, FILETIME *lpFt)
  136. {
  137. BOOL fRet=FALSE;
  138. char buff[256];
  139. DWORD dwBuffLen;
  140. dwBuffLen = sizeof(buff);
  141. if (HttpQueryInfo(hRequest, HTTP_QUERY_LAST_MODIFIED, NULL, buff, &dwBuffLen, NULL))
  142. {
  143. fRet = FParseHttpDate(lpFt, buff);
  144. }
  145. return fRet;
  146. }
  147. DWORD
  148. inline
  149. MapDayMonthToDword(
  150. LPCSTR lpszDay
  151. )
  152. /*++
  153. Routine Description:
  154. Looks at the first three bytes of string to determine if we're looking
  155. at a Day of the Week, or Month, or "GMT" string. Is inlined so that
  156. the compiler can optimize this code into the caller FInternalParseHttpDate.
  157. Arguments:
  158. lpszDay - a string ptr to the first byte of the string in question.
  159. Return Value:
  160. DWORD
  161. Success - The Correct date token, 0-6 for day of the week, 1-14 for month, etc
  162. Failure - DATE_TOKEN_ERROR
  163. --*/
  164. {
  165. switch ( MAKE_UPPER(*lpszDay) ) // make uppercase
  166. {
  167. case 'A':
  168. switch ( MAKE_UPPER(*(lpszDay+1)) )
  169. {
  170. case 'P':
  171. return DATE_TOKEN_APRIL;
  172. case 'U':
  173. return DATE_TOKEN_AUGUST;
  174. }
  175. return DATE_TOKEN_ERROR;
  176. case 'D':
  177. return DATE_TOKEN_DECEMBER;
  178. case 'F':
  179. switch ( MAKE_UPPER(*(lpszDay+1)) )
  180. {
  181. case 'R':
  182. return DATE_TOKEN_FRIDAY;
  183. case 'E':
  184. return DATE_TOKEN_FEBRUARY;
  185. }
  186. return DATE_TOKEN_ERROR;
  187. case 'G':
  188. return DATE_TOKEN_GMT;
  189. case 'M':
  190. switch ( MAKE_UPPER(*(lpszDay+1)) )
  191. {
  192. case 'O':
  193. return DATE_TOKEN_MONDAY;
  194. case 'A':
  195. switch (MAKE_UPPER(*(lpszDay+2)) )
  196. {
  197. case 'R':
  198. return DATE_TOKEN_MARCH;
  199. case 'Y':
  200. return DATE_TOKEN_MAY;
  201. }
  202. // fall through to error
  203. }
  204. return DATE_TOKEN_ERROR;
  205. case 'N':
  206. return DATE_TOKEN_NOVEMBER;
  207. case 'J':
  208. switch (MAKE_UPPER(*(lpszDay+1)) )
  209. {
  210. case 'A':
  211. return DATE_TOKEN_JANUARY;
  212. case 'U':
  213. switch (MAKE_UPPER(*(lpszDay+2)) )
  214. {
  215. case 'N':
  216. return DATE_TOKEN_JUNE;
  217. case 'L':
  218. return DATE_TOKEN_JULY;
  219. }
  220. // fall through to error
  221. }
  222. return DATE_TOKEN_ERROR;
  223. case 'O':
  224. return DATE_TOKEN_OCTOBER;
  225. case 'S':
  226. switch (MAKE_UPPER(*(lpszDay+1)) )
  227. {
  228. case 'A':
  229. return DATE_TOKEN_SATURDAY;
  230. case 'U':
  231. return DATE_TOKEN_SUNDAY;
  232. case 'E':
  233. return DATE_TOKEN_SEPTEMBER;
  234. }
  235. return DATE_TOKEN_ERROR;
  236. case 'T':
  237. switch (MAKE_UPPER(*(lpszDay+1)) )
  238. {
  239. case 'U':
  240. return DATE_TOKEN_TUESDAY;
  241. case 'H':
  242. return DATE_TOKEN_THURSDAY;
  243. }
  244. return DATE_TOKEN_ERROR;
  245. case 'U':
  246. return DATE_TOKEN_GMT;
  247. case 'W':
  248. return DATE_TOKEN_WEDNESDAY;
  249. }
  250. return DATE_TOKEN_ERROR;
  251. }
  252. BOOL
  253. FInternalParseHttpDate(
  254. OUT FILETIME *lpft,
  255. OUT SYSTEMTIME *lpSysTime,
  256. IN LPCSTR lpInputBuffer
  257. )
  258. /*++
  259. Routine Description:
  260. Parses through a ANSI, RFC850, or RFC1123 date format and covents it into
  261. a FILETIME/SYSTEMTIME time format.
  262. Important this a time-critical function and should only be changed
  263. with the intention of optimizing or a critical need work item.
  264. Arguments:
  265. lpft - Ptr to FILETIME structure. Used to store converted result.
  266. Must be NULL if not intended to be used !!!
  267. lpSysTime - Ptr to SYSTEMTIME struture. Used to return Systime if needed.
  268. lpcszDateStr - Const Date string to parse.
  269. Return Value:
  270. BOOL
  271. Success - TRUE
  272. Failure - FALSE
  273. --*/
  274. {
  275. int i = 0, iLastLettered = -1;
  276. BOOL fIsANSIDateFormat = FALSE;
  277. DWORD rgdwDateParseResults[MAX_DATE_ENTRIES];
  278. SYSTEMTIME sSysTime;
  279. FILETIME ftTime;
  280. BOOL fRet = TRUE;
  281. DEBUG_ENTER((DBG_HTTP,
  282. Bool,
  283. "FInternalParseHttpDate",
  284. "%x %.10q",
  285. lpft,
  286. lpInputBuffer
  287. ));
  288. //
  289. // Date Parsing v2 (1 more to go), and here is how it works...
  290. // We take a date string and churn through it once, converting
  291. // integers to integers, Month,Day, and GMT strings into integers,
  292. // and all is then placed IN order in a temp array.
  293. //
  294. // At the completetion of the parse stage, we simple look at
  295. // the data, and then map the results into the correct
  296. // places in the SYSTIME structure. Simple, No allocations, and
  297. // No dirting the data.
  298. //
  299. // The end of the function does something munging and pretting
  300. // up of the results to handle the year 2000, and TZ offsets
  301. // Note: do we need to fully handle TZs anymore?
  302. //
  303. memset(rgdwDateParseResults, 0, sizeof(rgdwDateParseResults));
  304. while ( *lpInputBuffer && i < MAX_DATE_ENTRIES)
  305. {
  306. if ( *lpInputBuffer >= '0' && *lpInputBuffer <= '9' )
  307. {
  308. //
  309. // we have a numerical entry, scan through it and convent to DWORD
  310. //
  311. rgdwDateParseResults[i] = 0;
  312. do {
  313. rgdwDateParseResults[i] *= BASE_DEC;
  314. rgdwDateParseResults[i] += (DWORD) (*lpInputBuffer - '0');
  315. lpInputBuffer++;
  316. } while ( *lpInputBuffer && *lpInputBuffer >= '0' && *lpInputBuffer <= '9' );
  317. i++; // next token
  318. }
  319. else if ( (*lpInputBuffer >= 'A' && *lpInputBuffer <= 'Z') ||
  320. (*lpInputBuffer >= 'a' && *lpInputBuffer <= 'z') )
  321. {
  322. //
  323. // we have a string, should be a day, month, or GMT
  324. // lets skim to the end of the string
  325. //
  326. rgdwDateParseResults[i] =
  327. MapDayMonthToDword(lpInputBuffer);
  328. iLastLettered = i;
  329. // We want to ignore the possibility of a time zone such as PST or EST in a non-standard
  330. // date format such as "Thu Dec 17 16:01:28 PST 1998" (Notice that the year is _after_ the time zone
  331. if ((rgdwDateParseResults[i] == DATE_TOKEN_ERROR)
  332. &&
  333. !(fIsANSIDateFormat && (i==DATE_ANSI_INDEX_YEAR)))
  334. {
  335. fRet = FALSE;
  336. #ifdef DEBUG
  337. dprintf("FInternalParseHttpDate: Invalid Date Format, could not parse %s\n", lpInputBuffer);
  338. #endif
  339. goto quit;
  340. }
  341. //
  342. // At this point if we have a vaild string
  343. // at this index, we know for sure that we're
  344. // looking at a ANSI type DATE format.
  345. //
  346. if ( i == DATE_ANSI_INDEX_MONTH )
  347. {
  348. fIsANSIDateFormat = TRUE;
  349. }
  350. //
  351. // Read past the end of the current set of alpha characters,
  352. // as MapDayMonthToDword only peeks at a few characters
  353. //
  354. do {
  355. lpInputBuffer++;
  356. } while ( *lpInputBuffer &&
  357. ( (*lpInputBuffer >= 'A' && *lpInputBuffer <= 'Z') ||
  358. (*lpInputBuffer >= 'a' && *lpInputBuffer <= 'z') ) );
  359. i++; // next token
  360. }
  361. else
  362. {
  363. //
  364. // For the generic case its either a space, comma, semi-colon, etc.
  365. // the point is we really don't care, nor do we need to waste time
  366. // worring about it (the orginal code did). The point is we
  367. // care about the actual date information, So we just advance to the
  368. // next lexume.
  369. //
  370. lpInputBuffer++;
  371. }
  372. }
  373. //
  374. // We're finished parsing the string, now take the parsed tokens
  375. // and turn them to the actual structured information we care about.
  376. // So we build lpSysTime from the Array, using a local if none is passed in.
  377. //
  378. if ( lpSysTime == NULL )
  379. {
  380. lpSysTime = &sSysTime;
  381. }
  382. lpSysTime->wDayOfWeek = (WORD)rgdwDateParseResults[DATE_INDEX_DAY_OF_WEEK];
  383. lpSysTime->wMilliseconds = 0;
  384. if ( fIsANSIDateFormat )
  385. {
  386. lpSysTime->wDay = (WORD)rgdwDateParseResults[DATE_ANSI_INDEX_DAY];
  387. lpSysTime->wMonth = (WORD)rgdwDateParseResults[DATE_ANSI_INDEX_MONTH];
  388. lpSysTime->wHour = (WORD)rgdwDateParseResults[DATE_ANSI_INDEX_HRS];
  389. lpSysTime->wMinute = (WORD)rgdwDateParseResults[DATE_ANSI_INDEX_MINS];
  390. lpSysTime->wSecond = (WORD)rgdwDateParseResults[DATE_ANSI_INDEX_SECS];
  391. if (iLastLettered != DATE_ANSI_INDEX_YEAR)
  392. {
  393. lpSysTime->wYear = (WORD)rgdwDateParseResults[DATE_ANSI_INDEX_YEAR];
  394. }
  395. else
  396. {
  397. // Warning! This is a hack to get around the toString/toGMTstring fiasco (where the timezone is
  398. // appended at the end. (See above)
  399. lpSysTime->wYear = (WORD)rgdwDateParseResults[DATE_INDEX_TZ];
  400. }
  401. }
  402. else
  403. {
  404. lpSysTime->wDay = (WORD)rgdwDateParseResults[DATE_1123_INDEX_DAY];
  405. lpSysTime->wMonth = (WORD)rgdwDateParseResults[DATE_1123_INDEX_MONTH];
  406. lpSysTime->wYear = (WORD)rgdwDateParseResults[DATE_1123_INDEX_YEAR];
  407. lpSysTime->wHour = (WORD)rgdwDateParseResults[DATE_1123_INDEX_HRS];
  408. lpSysTime->wMinute = (WORD)rgdwDateParseResults[DATE_1123_INDEX_MINS];
  409. lpSysTime->wSecond = (WORD)rgdwDateParseResults[DATE_1123_INDEX_SECS];
  410. }
  411. //
  412. // Normalize the year, 90 == 1990, handle the year 2000, 02 == 2002
  413. // This is Year 2000 handling folks!!! We get this wrong and
  414. // we all look bad.
  415. //
  416. if (lpSysTime->wYear < 100) {
  417. lpSysTime->wYear += ((lpSysTime->wYear < 80) ? 2000 : 1900);
  418. }
  419. //
  420. // if we got misformed time, then plug in the current time
  421. // !lpszHrs || !lpszMins || !lpszSec
  422. //
  423. if ( i < 4)
  424. {
  425. SYSTEMTIME sCurSysTime;
  426. // this is a bad date; logging.
  427. DEBUG_PRINT(HTTP,
  428. INFO,
  429. ("*** Received a malformed date: %s\n", lpInputBuffer
  430. ));
  431. GetSystemTime(&sCurSysTime);
  432. if ( i < 2 )
  433. {
  434. //
  435. // If we really messed up the parsing, then
  436. // just use the current time.
  437. //
  438. *lpSysTime = sCurSysTime;
  439. }
  440. else
  441. {
  442. lpSysTime->wHour = sCurSysTime.wHour;
  443. lpSysTime->wMinute = sCurSysTime.wMinute;
  444. lpSysTime->wSecond = sCurSysTime.wSecond;
  445. }
  446. }
  447. if ((lpSysTime->wDay > 31)
  448. || (lpSysTime->wHour > 23)
  449. || (lpSysTime->wMinute > 59)
  450. || (lpSysTime->wSecond > 59))
  451. {
  452. fRet = FALSE;
  453. DEBUG_PRINT(HTTP,
  454. INFO,
  455. ("*** Received a malformed date: %s\n", lpInputBuffer
  456. ));
  457. goto quit;
  458. }
  459. // Hack: we want the system time to be accurate. This is _suhlow_
  460. // The time passed in is in the local time zone; we have to convert this into GMT.
  461. if (iLastLettered==DATE_ANSI_INDEX_YEAR)
  462. {
  463. i--;
  464. FILETIME ft1, ft2;
  465. fRet =
  466. SystemTimeToFileTime(lpSysTime, &ft1);
  467. if (fRet)
  468. {
  469. fRet = LocalFileTimeToFileTime(&ft1, &ft2);
  470. if (fRet)
  471. {
  472. fRet = FileTimeToSystemTime(&ft2, lpSysTime);
  473. }
  474. }
  475. if (!fRet)
  476. {
  477. DEBUG_PRINT(HTTP,
  478. INFO,
  479. ("*** Received a malformed date: %s\n", lpInputBuffer
  480. ));
  481. goto quit;
  482. }
  483. }
  484. //
  485. // If FILETIME Ptr passed in/or we have an Offset to another Time Zone
  486. // then convert to FILETIME for necessity/convenience
  487. //
  488. if ( lpft ||
  489. (i > DATE_INDEX_TZ &&
  490. rgdwDateParseResults[DATE_INDEX_TZ] != DATE_TOKEN_GMT))
  491. {
  492. if ( lpft == NULL )
  493. {
  494. lpft = &ftTime;
  495. }
  496. fRet =
  497. SystemTimeToFileTime(lpSysTime, lpft);
  498. if ( ! fRet )
  499. {
  500. DEBUG_PRINT(HTTP,
  501. INFO,
  502. ("*** Received a malformed date: %s\n", lpInputBuffer
  503. ));
  504. goto quit;
  505. }
  506. if (i > DATE_INDEX_TZ &&
  507. rgdwDateParseResults[DATE_INDEX_TZ] != DATE_TOKEN_GMT)
  508. {
  509. // time zones are a very expensive operation, I want to know if this is a common case.
  510. DEBUG_PRINT(HTTP,
  511. INFO,
  512. ("*** Received a time zone: %d\n", (int) rgdwDateParseResults[DATE_INDEX_TZ]
  513. ));
  514. //
  515. // if we received +/-nnnn as offset (hhmm), modify the output FILETIME
  516. //
  517. LONGLONG delta;
  518. BOOL negative;
  519. int offset;
  520. offset = (int) rgdwDateParseResults[DATE_INDEX_TZ];
  521. //
  522. // BUGBUG - some sites return +0000 instead of GMT. Presumably, this is
  523. // an offset from GMT (== 0). What are the units? What are the
  524. // boundaries (-12 hours to +12 hours? In seconds? (43200
  525. // seconds in 12 hours, so can't be this)
  526. //
  527. //
  528. // BUGBUG - must handle negatives...and (-1 == GMT)
  529. //
  530. if (offset < 0) {
  531. negative = TRUE;
  532. offset = -offset;
  533. } else {
  534. negative = FALSE;
  535. }
  536. //
  537. // hours and minutes as 100nSec intervals
  538. //
  539. delta = (((offset / 100) * 60)
  540. + (offset % 100)) * 60 * 10000000;
  541. if (negative) {
  542. delta = -delta;
  543. }
  544. AddLongLongToFT(lpft,delta);
  545. //
  546. // Chk to see if we Need to turn the offseted
  547. // FILETIME back into SYSTEMTIME.
  548. //
  549. if ( lpSysTime == &sSysTime )
  550. {
  551. fRet = FileTimeToSystemTime(lpft, lpSysTime);
  552. }
  553. }
  554. }
  555. quit:
  556. DEBUG_LEAVE(fRet);
  557. return fRet;
  558. }
  559. PUBLIC
  560. BOOL
  561. FParseHttpDate(
  562. OUT FILETIME *lpft,
  563. IN LPCSTR lpInputBuffer
  564. )
  565. /*++
  566. Routine Description:
  567. Parses through a ANSI, RFC850, or RFC1123 date format and covents it into
  568. a FILETIME time format.
  569. Arguments:
  570. lpft - Ptr to FILETIME structure. Used to store converted result.
  571. lpcszDateStr - Const Date string to parse.
  572. Return Value:
  573. BOOL
  574. Success - TRUE
  575. Failure - FALSE
  576. --*/
  577. {
  578. return FInternalParseHttpDate(
  579. lpft,
  580. NULL, // SYSTEMTIME
  581. lpInputBuffer
  582. );
  583. }
  584. //+---------------------------------------------------------------------------
  585. //
  586. // Function: FFileTimetoHttpDateTime
  587. //
  588. // Synopsis:
  589. //
  590. // Arguments:
  591. //
  592. //
  593. // Returns: TRUE if successful. lpft contains the datetime in FILETIME format
  594. //
  595. //
  596. // Notes:
  597. //
  598. //
  599. //----------------------------------------------------------------------------
  600. BOOL FFileTimetoHttpDateTime(
  601. FILETIME *lpft, // output filetime in GMT
  602. LPSTR lpszBuff,
  603. LPDWORD lpdwSize
  604. )
  605. {
  606. SYSTEMTIME sSysTime;
  607. INET_ASSERT (*lpdwSize >= HTTP_DATE_SIZE);
  608. if (FileTimeToSystemTime(lpft, &sSysTime)) {
  609. *lpdwSize = wsprintf(lpszBuff, cszHttpDateFmt
  610. , rgszWkDay[sSysTime.wDayOfWeek]
  611. , sSysTime.wDay
  612. , rgszMon[sSysTime.wMonth-1]
  613. , sSysTime.wYear
  614. , sSysTime.wHour
  615. , sSysTime.wMinute
  616. , sSysTime.wSecond);
  617. return (TRUE);
  618. }
  619. return (FALSE);
  620. }
  621. BOOL
  622. HttpDateToSystemTime(
  623. IN LPSTR lpszHttpDate,
  624. OUT LPSYSTEMTIME lpSystemTime
  625. )
  626. /*++
  627. Routine Description:
  628. Takes a HTTP time/date string of the format "Sat, 6 Jan 1996 21:22:04 GMT"
  629. and converts it to a SYSTEMTIME structure
  630. Arguments:
  631. lpszHttpDate - pointer to time string to convert
  632. lpSystemTime - pointer to converted time
  633. Return Value:
  634. BOOL
  635. TRUE - string converted
  636. FALSE - couldn't convert string
  637. --*/
  638. {
  639. return FInternalParseHttpDate(
  640. NULL, // FILETIME
  641. lpSystemTime,
  642. (LPCSTR)lpszHttpDate
  643. );
  644. }
  645. INTERNETAPI
  646. BOOL
  647. WINAPI
  648. InternetTimeFromSystemTimeA(
  649. IN CONST SYSTEMTIME *pst, // input GMT time
  650. OUT LPSTR lpszTime // output string buffer
  651. )
  652. /*++
  653. Routine Description:
  654. Converts system time to a time string fromatted in the specified RFC format
  655. Arguments:
  656. pst: points to the SYSTEMTIME to be converted
  657. lpszTime: buffer to return the string in
  658. Return Value:
  659. BOOL
  660. TRUE - string converted
  661. FALSE - couldn't convert string, GetLastError returns windows error code
  662. --*/
  663. {
  664. DEBUG_ENTER_API((DBG_API,
  665. Handle,
  666. "InternetTimeFromSystemTimeA",
  667. "%#x, %#x",
  668. pst,
  669. lpszTime
  670. ));
  671. DWORD dwErr;
  672. BOOL fResult = TRUE;
  673. FILETIME ft;
  674. INET_ASSERT(!( IsBadReadPtr (pst, sizeof(*pst))
  675. || IsBadWritePtr (lpszTime, WINHTTP_TIME_FORMAT_BUFSIZE)
  676. || !SystemTimeToFileTime(pst, &ft)
  677. ));
  678. if (!SystemTimeToFileTime(pst, &ft))
  679. {
  680. fResult = FALSE;
  681. dwErr = ERROR_INVALID_PARAMETER;
  682. }
  683. else
  684. {
  685. SYSTEMTIME st;
  686. if (!FileTimeToSystemTime(&ft, &st))
  687. {
  688. // If a round trip isn't allowed (e.g. boundary case involving year
  689. // near 65535), then fail the call.
  690. fResult = FALSE;
  691. dwErr = ERROR_INVALID_PARAMETER;
  692. }
  693. else
  694. {
  695. // ST2FT ignores the week of the day; so if we round trip back,
  696. // it should place the correct week of the day.
  697. pst = &st;
  698. }
  699. if (fResult)
  700. {
  701. wsprintf (lpszTime, cszHttpDateFmt,
  702. rgszWkDay[pst->wDayOfWeek],
  703. pst->wDay,
  704. rgszMon[pst->wMonth-1],
  705. pst->wYear,
  706. pst->wHour,
  707. pst->wMinute,
  708. pst->wSecond);
  709. }
  710. }
  711. if (!fResult)
  712. {
  713. SetLastError(dwErr);
  714. DEBUG_ERROR(INET, dwErr);
  715. }
  716. DEBUG_LEAVE_API(fResult);
  717. return fResult;
  718. }
  719. INTERNETAPI
  720. BOOL
  721. WINAPI
  722. InternetTimeToSystemTimeA(
  723. IN LPCSTR lpcszTimeString,
  724. OUT SYSTEMTIME *lpSysTime,
  725. IN DWORD dwReserved
  726. )
  727. /*++
  728. Routine Description:
  729. API. Takes a HTTP time/date string of the formats that we deal with
  730. and converts it to a SYSTEMTIME structure
  731. Arguments:
  732. lpcszTimeString - pointer to a null terminated date/time string to convert
  733. lpSysTime - pointer to converted time
  734. dwreserved - Reserved
  735. Return Value:
  736. BOOL
  737. TRUE - string converted
  738. FALSE - couldn't convert string, GetLastError returns windows error code
  739. --*/
  740. {
  741. DEBUG_ENTER_API((DBG_API,
  742. Handle,
  743. "InternetTimeToSystemTimeA",
  744. "%q, %#x, %#x",
  745. lpcszTimeString,
  746. lpSysTime,
  747. dwReserved
  748. ));
  749. BOOL fRet;;
  750. INET_ASSERT(! (IsBadWritePtr (lpSysTime, sizeof(*lpSysTime))
  751. || IsBadStringPtr(lpcszTimeString, 0xffff)) );
  752. fRet = FInternalParseHttpDate(NULL, lpSysTime, (LPCSTR)lpcszTimeString);
  753. if (!fRet)
  754. {
  755. SetLastError(ERROR_INVALID_PARAMETER);
  756. DEBUG_ERROR(INET, ERROR_INVALID_PARAMETER);
  757. }
  758. DEBUG_LEAVE_API(fRet);
  759. return (fRet);
  760. }
  761. INTERNETAPI
  762. BOOL
  763. WINAPI
  764. WinHttpTimeFromSystemTime(
  765. IN CONST SYSTEMTIME *pst, // input GMT time
  766. OUT LPWSTR lpszTime // output string buffer
  767. )
  768. /*++
  769. Routine Description:
  770. Converts system time to a time string fromatted in the specified RFC format
  771. Arguments:
  772. pst: points to the SYSTEMTIME to be converted
  773. lpszTime: buffer to return the string in
  774. Return Value:
  775. BOOL
  776. TRUE - string converted
  777. FALSE - couldn't convert string, GetLastError returns windows error code
  778. --*/
  779. {
  780. DEBUG_ENTER_API((DBG_API,
  781. Handle,
  782. "WinHttpTimeFromSystemTimeW",
  783. "%#x, %#x",
  784. pst,
  785. lpszTime
  786. ));
  787. DWORD dwErr = ERROR_SUCCESS;;
  788. BOOL fResult = FALSE;
  789. MEMORYPACKET mpTime;
  790. DWORD ccSize;
  791. if (!lpszTime
  792. || IsBadWritePtr(lpszTime, WINHTTP_TIME_FORMAT_BUFSIZE)
  793. || !pst
  794. || IsBadReadPtr(pst, sizeof(*pst)))
  795. {
  796. dwErr = ERROR_INVALID_PARAMETER;
  797. goto cleanup;
  798. }
  799. mpTime.psStr = (LPSTR)ALLOC_BYTES(WINHTTP_TIME_FORMAT_BUFSIZE);
  800. if (!mpTime.psStr)
  801. {
  802. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  803. goto cleanup;
  804. }
  805. mpTime.dwAlloc = WINHTTP_TIME_FORMAT_BUFSIZE;
  806. fResult = InternetTimeFromSystemTimeA(pst, mpTime.psStr);
  807. if (fResult)
  808. {
  809. if (0 == MultiByteToWideChar(CP_ACP, 0, mpTime.psStr, -1, lpszTime, WINHTTP_TIME_FORMAT_BUFSIZE/sizeof(WCHAR)))
  810. {
  811. INET_ASSERT(FALSE);
  812. fResult = FALSE;
  813. dwErr = ERROR_INSUFFICIENT_BUFFER;;
  814. }
  815. }
  816. cleanup:
  817. if (dwErr!=ERROR_SUCCESS)
  818. {
  819. SetLastError(dwErr);
  820. DEBUG_ERROR(INET, dwErr);
  821. }
  822. DEBUG_LEAVE_API(fResult);
  823. return fResult;
  824. }
  825. INTERNETAPI
  826. BOOL
  827. WINAPI
  828. WinHttpTimeToSystemTime(
  829. IN LPCWSTR lpcszTimeString,
  830. OUT SYSTEMTIME *lpSysTime
  831. )
  832. /*++
  833. Routine Description:
  834. API. Takes a HTTP time/date string of the formats that we deal with
  835. and converts it to a SYSTEMTIME structure
  836. Arguments:
  837. lpcszTimeString - pointer to a null terminated date/time string to convert
  838. lpSysTime - pointer to converted time
  839. Return Value:
  840. BOOL
  841. TRUE - string converted
  842. FALSE - couldn't convert string, GetLastError returns windows error code
  843. --*/
  844. {
  845. DEBUG_ENTER_API((DBG_API,
  846. Handle,
  847. "WinHttpTimeFromSystemTime",
  848. "%wq, %#x",
  849. lpcszTimeString,
  850. lpSysTime
  851. ));
  852. DWORD dwErr = ERROR_SUCCESS;
  853. BOOL fResult = FALSE;
  854. MEMORYPACKET mpTime;
  855. if (!lpcszTimeString
  856. || IsBadStringPtrW(lpcszTimeString,-1)
  857. || !lpSysTime
  858. || IsBadWritePtr(lpSysTime,sizeof(SYSTEMTIME)) )
  859. {
  860. dwErr = ERROR_INVALID_PARAMETER;
  861. goto cleanup;
  862. }
  863. ALLOC_MB(lpcszTimeString, 0, mpTime);
  864. if (!mpTime.psStr)
  865. {
  866. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  867. goto cleanup;
  868. }
  869. UNICODE_TO_ANSI(lpcszTimeString, mpTime);
  870. fResult = InternetTimeToSystemTimeA(mpTime.psStr, lpSysTime, NULL);
  871. cleanup:
  872. if (dwErr!=ERROR_SUCCESS)
  873. {
  874. SetLastError(dwErr);
  875. DEBUG_ERROR(INET, dwErr);
  876. }
  877. DEBUG_LEAVE_API(fResult);
  878. return fResult;
  879. }