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.

550 lines
12 KiB

  1. #include <syncobj.hxx>
  2. #define INITIAL_HEADERS_COUNT 16
  3. #define HEADERS_INCREMENT 4
  4. #define INVALID_HEADER_INDEX 0xff
  5. #define INVALID_HEADER_SLOT 0xFFFFFFFF
  6. //
  7. // STRESS_BUG_DEBUG - used to catch a specific stress fault,
  8. // where we have a corrupted crit sec.
  9. //
  10. #define CLEAR_DEBUG_CRIT(x)
  11. #define IS_DEBUG_CRIT_OK(x)
  12. typedef enum {
  13. HTTP_METHOD_TYPE_UNKNOWN = -1,
  14. HTTP_METHOD_TYPE_FIRST = 0,
  15. HTTP_METHOD_TYPE_GET= HTTP_METHOD_TYPE_FIRST,
  16. HTTP_METHOD_TYPE_HEAD,
  17. HTTP_METHOD_TYPE_POST,
  18. HTTP_METHOD_TYPE_PUT,
  19. HTTP_METHOD_TYPE_PROPFIND,
  20. HTTP_METHOD_TYPE_PROPPATCH,
  21. HTTP_METHOD_TYPE_LOCK,
  22. HTTP_METHOD_TYPE_UNLOCK,
  23. HTTP_METHOD_TYPE_COPY,
  24. HTTP_METHOD_TYPE_MOVE,
  25. HTTP_METHOD_TYPE_MKCOL,
  26. HTTP_METHOD_TYPE_CONNECT,
  27. HTTP_METHOD_TYPE_DELETE,
  28. HTTP_METHOD_TYPE_LINK,
  29. HTTP_METHOD_TYPE_UNLINK,
  30. HTTP_METHOD_TYPE_BMOVE,
  31. HTTP_METHOD_TYPE_BCOPY,
  32. HTTP_METHOD_TYPE_BPROPFIND,
  33. HTTP_METHOD_TYPE_BPROPPATCH,
  34. HTTP_METHOD_TYPE_BDELETE,
  35. HTTP_METHOD_TYPE_SUBSCRIBE,
  36. HTTP_METHOD_TYPE_UNSUBSCRIBE,
  37. HTTP_METHOD_TYPE_NOTIFY,
  38. HTTP_METHOD_TYPE_POLL,
  39. HTTP_METHOD_TYPE_CHECKIN,
  40. HTTP_METHOD_TYPE_CHECKOUT,
  41. HTTP_METHOD_TYPE_INVOKE,
  42. HTTP_METHOD_TYPE_SEARCH,
  43. HTTP_METHOD_TYPE_PIN,
  44. HTTP_METHOD_TYPE_MPOST,
  45. HTTP_METHOD_TYPE_LAST = HTTP_METHOD_TYPE_MPOST
  46. } HTTP_METHOD_TYPE;
  47. //
  48. // HTTP_HEADERS - array of pointers to general HTTP header strings. Headers are
  49. // stored without line termination. _HeadersLength maintains the cumulative
  50. // amount of buffer space required to store all the headers. Accounts for the
  51. // missing line termination sequence
  52. //
  53. #define HTTP_HEADER_SIGNATURE 0x64616548 // "Head"
  54. class HTTP_HEADERS {
  55. public:
  56. //
  57. // _bKnownHeaders - array of bytes which index into lpHeaders
  58. // the 0 column is an error catcher, so all indexes need to be biased by 1 (++'ed)
  59. //
  60. BYTE _bKnownHeaders[HTTP_QUERY_MAX+2];
  61. private:
  62. #if INET_DEBUG
  63. DWORD _Signature;
  64. #endif
  65. //
  66. // _lpHeaders - (growable) array of pointers to headers added by app
  67. //
  68. HEADER_STRING * _lpHeaders;
  69. //
  70. // _TotalSlots - number of pointers in (i.e. size of) _lpHeaders
  71. //
  72. DWORD _TotalSlots;
  73. //
  74. // _NextOpenSlot - offset where the next array is open for allocation
  75. //
  76. DWORD _NextOpenSlot;
  77. //
  78. // _FreeSlots - number of available headers in _lpHeaders
  79. //
  80. DWORD _FreeSlots;
  81. //
  82. // _HeadersLength - the amount of buffer space required to store the headers.
  83. // For each header, includes +2 for the line termination that must be added
  84. // when the header buffer is generated, or when the headers are queried
  85. //
  86. DWORD _HeadersLength;
  87. //
  88. // _IsRequestHeaders - TRUE if this HTTP_HEADERS object describes the
  89. // request headers
  90. //
  91. BOOL _IsRequestHeaders;
  92. //
  93. // _lpszVerb etc. - in the case of request headers, we maintain these
  94. // pointers and corresponding lengths to make modifying the request line
  95. // easier in the case of a redirect
  96. //
  97. // N.B. The pointers are just offsets into the request line AND MUST NOT BE
  98. // FREED
  99. //
  100. LPSTR _lpszVerb;
  101. DWORD _dwVerbLength;
  102. LPSTR _lpszObjectName;
  103. DWORD _dwObjectNameLength;
  104. LPSTR _lpszVersion;
  105. DWORD _dwVersionLength;
  106. DWORD _RequestVersionMajor;
  107. DWORD _RequestVersionMinor;
  108. //
  109. // _Error - status code if error
  110. //
  111. DWORD _Error;
  112. //
  113. // _CritSec - acquire this when accessing header structure - stops multiple
  114. // threads clashing while modifying headers
  115. //
  116. // Question: why do we allow multi-threaded access to headers on same request?
  117. //
  118. CCritSec _CritSec;
  119. //
  120. // private methods
  121. //
  122. DWORD
  123. AllocateHeaders(
  124. IN DWORD dwNumberOfHeaders
  125. );
  126. public:
  127. HTTP_HEADERS() {
  128. #if INET_DEBUG
  129. _Signature = HTTP_HEADER_SIGNATURE;
  130. #endif
  131. CLEAR_DEBUG_CRIT(_szCritSecBefore);
  132. CLEAR_DEBUG_CRIT(_szCritSecAfter);
  133. _CritSec.Init();
  134. Initialize();
  135. }
  136. ~HTTP_HEADERS() {
  137. DEBUG_ENTER((DBG_OBJECTS,
  138. None,
  139. "~HTTP_HEADERS",
  140. "%#x",
  141. this
  142. ));
  143. #if INET_DEBUG
  144. INET_ASSERT(_Signature == HTTP_HEADER_SIGNATURE);
  145. #endif
  146. FreeHeaders();
  147. DEBUG_LEAVE(0);
  148. }
  149. VOID Initialize(VOID) {
  150. _lpHeaders = NULL;
  151. _TotalSlots = 0;
  152. _FreeSlots = 0;
  153. _HeadersLength = 0;
  154. _lpszVerb = NULL;
  155. _dwVerbLength = 0;
  156. _lpszObjectName = NULL;
  157. _dwObjectNameLength = 0;
  158. _lpszVersion = NULL;
  159. _dwVersionLength = 0;
  160. _RequestVersionMajor = 0;
  161. _RequestVersionMinor = 0;
  162. _NextOpenSlot = 0;
  163. memset((void *) _bKnownHeaders, INVALID_HEADER_SLOT, ARRAY_ELEMENTS(_bKnownHeaders));
  164. _Error = AllocateHeaders(INITIAL_HEADERS_COUNT);
  165. }
  166. BOOL IsHeaderPresent(DWORD dwQueryIndex) const {
  167. return (_bKnownHeaders[dwQueryIndex] != INVALID_HEADER_INDEX) ? TRUE : FALSE ;
  168. }
  169. BOOL LockHeaders(VOID) {
  170. return _CritSec.Lock();
  171. }
  172. VOID UnlockHeaders(VOID) {
  173. _CritSec.Unlock();
  174. }
  175. VOID
  176. FreeHeaders(
  177. VOID
  178. );
  179. DWORD
  180. CopyHeaders(
  181. IN OUT LPSTR * lpBuffer,
  182. IN LPSTR lpszObjectName,
  183. IN DWORD dwObjectNameLength
  184. );
  185. #ifdef COMPRESSED_HEADERS
  186. VOID
  187. CopyCompressedHeaders(
  188. IN OUT LPSTR * lpBuffer
  189. );
  190. #endif //COMPRESSED_HEADERS
  191. HEADER_STRING *
  192. FASTCALL
  193. FindFreeSlot(
  194. DWORD* piSlot
  195. );
  196. HEADER_STRING *
  197. GetSlot(
  198. DWORD iSlot
  199. )
  200. {
  201. return &_lpHeaders[iSlot];
  202. }
  203. LPSTR GetHeaderPointer (LPBYTE pbBase, DWORD iSlot)
  204. {
  205. INET_ASSERT (iSlot < _TotalSlots);
  206. return _lpHeaders[iSlot].StringAddress((LPSTR) pbBase);
  207. }
  208. VOID
  209. ShrinkHeader(
  210. LPBYTE pbBase,
  211. DWORD iSlot,
  212. DWORD dwOldQueryIndex,
  213. DWORD dwNewQueryIndex,
  214. DWORD cbNewSize
  215. );
  216. DWORD
  217. inline
  218. FastFind(
  219. IN DWORD dwQueryIndex,
  220. IN DWORD dwIndex
  221. );
  222. DWORD
  223. inline
  224. FastNukeFind(
  225. IN DWORD dwQueryIndex,
  226. IN DWORD dwIndex,
  227. OUT BYTE **lplpbPrevIndex
  228. );
  229. DWORD
  230. inline
  231. SlowFind(
  232. IN LPSTR lpBase,
  233. IN LPCSTR lpszHeaderName,
  234. IN DWORD dwHeaderNameLength,
  235. IN DWORD dwIndex,
  236. IN DWORD dwHash,
  237. OUT DWORD *lpdwQueryIndex,
  238. OUT BYTE **lplpbPrevIndex
  239. );
  240. BYTE
  241. inline
  242. FastAdd(
  243. IN DWORD dwQueryIndex,
  244. IN DWORD dwSlot
  245. );
  246. BOOL
  247. inline
  248. HeaderMatch(
  249. IN DWORD dwHash,
  250. IN LPSTR lpszHeaderName,
  251. IN DWORD dwHeaderNameLength,
  252. OUT DWORD *lpdwQueryIndex
  253. );
  254. VOID
  255. RemoveAllByIndex(
  256. IN DWORD dwQueryIndex
  257. );
  258. VOID RemoveHeader(IN DWORD dwIndex, IN DWORD dwQueryIndex, IN BYTE *pbPrevByte) {
  259. INET_ASSERT(dwIndex < _TotalSlots);
  260. INET_ASSERT(dwIndex != 0);
  261. // INET_ASSERT(_HeadersLength > 2);
  262. INET_ASSERT(_lpHeaders[dwIndex].StringLength() > 2);
  263. INET_ASSERT(_FreeSlots <= _TotalSlots);
  264. //
  265. // remove the length of the header + 2 for CR-LF from the total headers
  266. // length
  267. //
  268. if (_HeadersLength) {
  269. _HeadersLength -= _lpHeaders[dwIndex].StringLength()
  270. + (sizeof("\r\n") - 1)
  271. ;
  272. }
  273. //
  274. // Update the cached known headers, if this is one.
  275. //
  276. if ( dwQueryIndex < INVALID_HEADER_INDEX )
  277. {
  278. *pbPrevByte = (BYTE) _lpHeaders[dwIndex].GetNextKnownIndex();
  279. }
  280. //
  281. // set the header string to NULL. Frees the header buffer
  282. //
  283. _lpHeaders[dwIndex] = (LPSTR)NULL;
  284. //
  285. // we have freed a slot in the headers array
  286. //
  287. if ( _FreeSlots == 0 )
  288. {
  289. _NextOpenSlot = dwIndex;
  290. }
  291. ++_FreeSlots;
  292. INET_ASSERT(_FreeSlots <= _TotalSlots);
  293. }
  294. DWORD GetSlotsInUse (void) {
  295. return _TotalSlots - _FreeSlots;
  296. }
  297. DWORD HeadersLength(VOID) const {
  298. return _HeadersLength;
  299. }
  300. DWORD ObjectNameLength(VOID) const {
  301. return _dwObjectNameLength;
  302. }
  303. LPSTR ObjectName(VOID) const {
  304. return _lpszObjectName;
  305. }
  306. DWORD
  307. AddHeader(
  308. IN LPSTR lpszHeaderName,
  309. IN DWORD dwHeaderNameLength,
  310. IN LPSTR lpszHeaderValue,
  311. IN DWORD dwHeaderValueLength,
  312. IN DWORD dwIndex,
  313. IN DWORD dwFlags
  314. );
  315. DWORD
  316. AddHeader(
  317. IN DWORD dwQueryIndex,
  318. IN LPSTR lpszHeaderValue,
  319. IN DWORD dwHeaderValueLength,
  320. IN DWORD dwIndex,
  321. IN DWORD dwFlags
  322. );
  323. DWORD
  324. ReplaceHeader(
  325. IN LPSTR lpszHeaderName,
  326. IN DWORD dwHeaderNameLength,
  327. IN LPSTR lpszHeaderValue,
  328. IN DWORD dwHeaderValueLength,
  329. IN DWORD dwIndex,
  330. IN DWORD dwFlags
  331. );
  332. DWORD
  333. ReplaceHeader(
  334. IN DWORD dwQueryIndex,
  335. IN LPSTR lpszHeaderValue,
  336. IN DWORD dwHeaderValueLength,
  337. IN DWORD dwIndex,
  338. IN DWORD dwFlags
  339. );
  340. DWORD
  341. FindHeader(
  342. IN LPSTR lpBase,
  343. IN LPCSTR lpszHeaderName,
  344. IN DWORD dwHeaderNameLength,
  345. IN DWORD dwModifiers,
  346. OUT LPVOID lpBuffer,
  347. IN OUT LPDWORD lpdwBufferLength,
  348. IN OUT LPDWORD lpdwIndex
  349. );
  350. DWORD
  351. FindHeader(
  352. IN LPSTR lpBase,
  353. IN DWORD dwQueryIndex,
  354. IN DWORD dwModifiers,
  355. OUT LPVOID lpBuffer,
  356. IN OUT LPDWORD lpdwBufferLength,
  357. IN OUT LPDWORD lpdwIndex
  358. );
  359. DWORD
  360. FastFindHeader(
  361. IN LPSTR lpBase,
  362. IN DWORD dwQueryIndex,
  363. OUT LPVOID *lplpBuffer,
  364. IN OUT LPDWORD lpdwBufferLength,
  365. IN OUT DWORD dwIndex
  366. );
  367. DWORD
  368. QueryRawHeaders(
  369. IN LPSTR lpBase,
  370. IN BOOL bCrLfTerminated,
  371. IN LPVOID lpBuffer,
  372. IN OUT LPDWORD lpdwBufferLength
  373. );
  374. DWORD
  375. QueryFilteredRawHeaders(
  376. IN LPSTR lpBase,
  377. IN LPSTR *lplpFilterList,
  378. IN DWORD cListElements,
  379. IN BOOL fExclude,
  380. IN BOOL fSkipVerb,
  381. IN BOOL bCrLfTerminated,
  382. IN LPVOID lpBuffer,
  383. IN OUT LPDWORD lpdwBufferLength
  384. );
  385. DWORD
  386. AddRequest(
  387. IN LPSTR lpszVerb,
  388. IN LPSTR lpszObjectName,
  389. IN LPSTR lpszVersion
  390. );
  391. DWORD
  392. ModifyRequest(
  393. IN HTTP_METHOD_TYPE tMethod,
  394. IN LPSTR lpszObjectName,
  395. IN DWORD dwObjectNameLength,
  396. IN LPSTR lpszVersion OPTIONAL,
  397. IN DWORD dwVersionLength
  398. );
  399. HEADER_STRING * GetFirstHeader(VOID) const {
  400. INET_ASSERT(_lpHeaders != NULL);
  401. return _lpHeaders;
  402. }
  403. HEADER_STRING * GetEmptyHeader(VOID) const {
  404. for (DWORD i = 0; i < _TotalSlots; ++i) {
  405. if (_lpHeaders[i].HaveString() && _lpHeaders[i].StringLength() == 0) {
  406. return &_lpHeaders[i];
  407. }
  408. }
  409. return NULL;
  410. }
  411. VOID SetIsRequestHeaders(BOOL bRequestHeaders) {
  412. _IsRequestHeaders = bRequestHeaders;
  413. }
  414. DWORD GetError(VOID) const {
  415. return _Error;
  416. }
  417. LPSTR GetVerb(LPDWORD lpdwVerbLength) const {
  418. *lpdwVerbLength = _dwVerbLength;
  419. return _lpszVerb;
  420. }
  421. //VOID SetRequestVersion(DWORD dwMajor, DWORD dwMinor) {
  422. // _RequestVersionMajor = dwMajor;
  423. // _RequestVersionMinor = dwMinor;
  424. //}
  425. VOID
  426. SetRequestVersion(
  427. VOID
  428. );
  429. DWORD MajorVersion(VOID) const {
  430. return _RequestVersionMajor;
  431. }
  432. DWORD MinorVersion(VOID) const {
  433. return _RequestVersionMinor;
  434. }
  435. };