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.

639 lines
18 KiB

  1. /*++
  2. Copyright (c) 1994 Microsoft Corporation
  3. Module Name:
  4. open.cxx
  5. Abstract:
  6. This file contains the implementation of the HttpOpenRequestA API.
  7. The following functions are exported by this module:
  8. HttpOpenRequestA
  9. WinHttpOpenRequest
  10. ParseHttpUrl
  11. ParseHttpUrl_Fsm
  12. Author:
  13. Keith Moore (keithmo) 16-Nov-1994
  14. Revision History:
  15. Modified to make HttpOpenRequestA remotable. madana (2/8/95)
  16. --*/
  17. #include <wininetp.h>
  18. #include "httpp.h"
  19. //
  20. // functions
  21. //
  22. INTERNETAPI
  23. HINTERNET
  24. WINAPI
  25. HttpOpenRequestA(
  26. IN HINTERNET hConnect,
  27. IN LPCSTR lpszVerb OPTIONAL,
  28. IN LPCSTR lpszObjectName OPTIONAL,
  29. IN LPCSTR lpszVersion OPTIONAL,
  30. IN LPCSTR lpszReferrer OPTIONAL,
  31. IN LPCSTR FAR * lplpszAcceptTypes OPTIONAL,
  32. IN DWORD dwFlags,
  33. IN DWORD_PTR dwContext
  34. )
  35. /*++
  36. Routine Description:
  37. Creates a new HTTP request handle and stores the specified parameters
  38. in that context.
  39. Arguments:
  40. hConnect - An open Internet handle returned by InternetConnect()
  41. lpszVerb - The verb to use in the request. May be NULL in which
  42. case "GET" will be used
  43. lpszObjectName - The target object for the specified verb. This is
  44. typically a file name, an executable module, or a
  45. search specifier. May be NULL in which case the empty
  46. string will be used
  47. lpszVersion - The version string for the request. May be NULL in
  48. which case "HTTP/1.0" will be used
  49. lpszReferrer - Specifies the address (URI) of the document from
  50. which the URI in the request (lpszObjectName) was
  51. obtained. May be NULL in which case no referer is
  52. specified
  53. lplpszAcceptTypes - Points to a NULL-terminated array of LPCTSTR pointers
  54. to content-types accepted by the client. This value
  55. may be NULL in which case the default content-type
  56. (text/html) is used
  57. dwFlags - open options
  58. dwContext - app-supplied context value for call-backs
  59. BUGBUG: WHAT IS THE DEFAULT CONTENT-TRANSFER-ENCODING?
  60. Return Value:
  61. HINTERNET
  62. Success - non-NULL (open) handle to an HTTP request
  63. Failure - NULL. Error status is available by calling GetLastError()
  64. --*/
  65. {
  66. DEBUG_ENTER_API((DBG_API,
  67. Handle,
  68. "HttpOpenRequestA",
  69. "%#x, %.80q, %.80q, %.80q, %.80q, %#x, %#08x, %#08x",
  70. hConnect,
  71. lpszVerb,
  72. lpszObjectName,
  73. lpszVersion,
  74. lpszReferrer,
  75. lplpszAcceptTypes,
  76. dwFlags,
  77. dwContext
  78. ));
  79. DWORD error;
  80. HINTERNET hConnectMapped = NULL;
  81. BOOL fRequestUsingProxy;
  82. HINTERNET hRequest = NULL;
  83. if (!GlobalDataInitialized) {
  84. error = ERROR_WINHTTP_NOT_INITIALIZED;
  85. goto done;
  86. }
  87. //
  88. // get the per-thread info
  89. //
  90. LPINTERNET_THREAD_INFO lpThreadInfo;
  91. lpThreadInfo = InternetGetThreadInfo();
  92. if (lpThreadInfo == NULL) {
  93. error = ERROR_WINHTTP_INTERNAL_ERROR;
  94. goto done;
  95. }
  96. _InternetIncNestingCount();
  97. //
  98. // map the handle
  99. //
  100. error = MapHandleToAddress(hConnect, (LPVOID *)&hConnectMapped, FALSE);
  101. if (error != ERROR_SUCCESS) {
  102. goto quit;
  103. }
  104. //
  105. // find path from internet handle and validate handle
  106. //
  107. BOOL isLocal;
  108. BOOL isAsync;
  109. error = RIsHandleLocal(hConnectMapped,
  110. &isLocal,
  111. &isAsync,
  112. TypeHttpConnectHandle
  113. );
  114. if (error != ERROR_SUCCESS) {
  115. goto quit;
  116. }
  117. //
  118. // validate parameters. Allow lpszVerb to default to "GET" if a NULL pointer
  119. // is supplied
  120. //
  121. if (!ARGUMENT_PRESENT(lpszVerb) || (*lpszVerb == '\0')) {
  122. lpszVerb = DEFAULT_HTTP_REQUEST_VERB;
  123. }
  124. //
  125. // if a NULL pointer or empty string is supplied for the object name, then
  126. // convert to the default object name (root object)
  127. //
  128. if (!ARGUMENT_PRESENT(lpszObjectName) || (*lpszObjectName == '\0')) {
  129. lpszObjectName = "/";
  130. }
  131. // check the rest of the parameters
  132. if (dwFlags & ~WINHTTP_OPEN_REQUEST_FLAGS_MASK)
  133. {
  134. error = ERROR_INVALID_PARAMETER;
  135. goto quit;
  136. }
  137. // default to the current supported version
  138. char versionBuffer[sizeof("HTTP/4294967295.4294967295")];
  139. DWORD verMajor;
  140. DWORD verMinor;
  141. if (!ARGUMENT_PRESENT(lpszVersion) || (*lpszVersion == '\0')) {
  142. wsprintf(versionBuffer,
  143. "HTTP/%d.%d",
  144. HttpVersionInfo.dwMajorVersion,
  145. HttpVersionInfo.dwMinorVersion
  146. );
  147. lpszVersion = versionBuffer;
  148. verMajor = HttpVersionInfo.dwMajorVersion;
  149. verMinor = HttpVersionInfo.dwMinorVersion;
  150. } else if (strnicmp(lpszVersion, "HTTP/", sizeof("HTTP/") - 1) == 0) {
  151. LPSTR p = (LPSTR)lpszVersion + sizeof("HTTP/") - 1;
  152. ExtractInt(&p, 0, (LPINT)&verMajor);
  153. while (!isdigit(*p) && (*p != '\0')) {
  154. ++p;
  155. }
  156. ExtractInt(&p, 0, (LPINT)&verMinor);
  157. } else {
  158. verMajor = 1;
  159. verMinor = 0;
  160. }
  161. //
  162. // if we have HTTP 1.1 enabled in the registry and the version is < 1.1
  163. // then convert
  164. //
  165. if (GlobalEnableHttp1_1
  166. && (((verMajor == 1) && (verMinor == 0)) || (verMajor < 1))) {
  167. lpszVersion = "HTTP/1.1";
  168. }
  169. //
  170. // allow empty strings to be equivalent to NULL pointer
  171. //
  172. if (ARGUMENT_PRESENT(lpszReferrer) && (*lpszReferrer == '\0')) {
  173. lpszReferrer = NULL;
  174. }
  175. // get the target port
  176. INTERNET_CONNECT_HANDLE_OBJECT * pConnect;
  177. pConnect = (INTERNET_CONNECT_HANDLE_OBJECT *)hConnectMapped;
  178. INTERNET_PORT hostPort;
  179. hostPort = pConnect->GetHostPort();
  180. //
  181. // set the per-thread info: parent handle object
  182. //
  183. _InternetSetObjectHandle(lpThreadInfo, hConnect, hConnectMapped);
  184. //
  185. // make local HTTP request handle object before we can add headers to it
  186. //
  187. error = RMakeHttpReqObjectHandle(hConnectMapped,
  188. &hRequest,
  189. NULL, // (CLOSE_HANDLE_FUNC)wHttpCloseRequest
  190. dwFlags,
  191. dwContext
  192. );
  193. if (error != ERROR_SUCCESS) {
  194. goto quit;
  195. }
  196. HTTP_REQUEST_HANDLE_OBJECT * pRequest;
  197. pRequest = (HTTP_REQUEST_HANDLE_OBJECT *)hRequest;
  198. //
  199. // add the request line
  200. //
  201. INET_ASSERT((lpszVerb != NULL) && (*lpszVerb != '\0'));
  202. INET_ASSERT((lpszObjectName != NULL) && (*lpszObjectName != '\0'));
  203. INET_ASSERT((lpszVersion != NULL) && (*lpszVersion != '\0'));
  204. if (!pRequest->LockHeaders())
  205. {
  206. error = ERROR_NOT_ENOUGH_MEMORY;
  207. goto quit;
  208. }
  209. //
  210. // encode the URL-path
  211. //
  212. error = pRequest->AddRequest((LPSTR)lpszVerb,
  213. (LPSTR)lpszObjectName,
  214. (LPSTR)lpszVersion
  215. );
  216. if (error != ERROR_SUCCESS) {
  217. pRequest->UnlockHeaders();
  218. goto quit;
  219. }
  220. //
  221. // set the method type from the verb
  222. //
  223. pRequest->SetMethodType(lpszVerb);
  224. //
  225. // add the headers
  226. //
  227. if (lpszReferrer != NULL) {
  228. error = pRequest->AddRequestHeader(HTTP_QUERY_REFERER,
  229. (LPSTR)lpszReferrer,
  230. lstrlen(lpszReferrer),
  231. 0,
  232. CLEAN_HEADER
  233. );
  234. if (error != ERROR_SUCCESS) {
  235. pRequest->UnlockHeaders();
  236. goto quit;
  237. }
  238. }
  239. if (lplpszAcceptTypes != NULL) {
  240. while (*lplpszAcceptTypes) {
  241. error = pRequest->AddRequestHeader(HTTP_QUERY_ACCEPT,
  242. (LPSTR)*lplpszAcceptTypes,
  243. lstrlen(*(LPSTR*)lplpszAcceptTypes),
  244. 0,
  245. CLEAN_HEADER | COALESCE_HEADER_WITH_COMMA
  246. );
  247. if (error != ERROR_SUCCESS) {
  248. pRequest->UnlockHeaders();
  249. goto quit;
  250. }
  251. ++lplpszAcceptTypes;
  252. }
  253. }
  254. INET_ASSERT(error == ERROR_SUCCESS);
  255. pRequest->UnlockHeaders();
  256. //
  257. // change the object state to opened
  258. //
  259. pRequest->SetState(HttpRequestStateOpen);
  260. ((HTTP_REQUEST_HANDLE_OBJECT *)hRequest)->SetRequestUsingProxy(
  261. FALSE
  262. );
  263. if (hostPort == INTERNET_INVALID_PORT_NUMBER)
  264. {
  265. if (dwFlags & WINHTTP_FLAG_SECURE)
  266. {
  267. pRequest->SetHostPort(INTERNET_DEFAULT_HTTPS_PORT);
  268. }
  269. else
  270. {
  271. pRequest->SetHostPort(INTERNET_DEFAULT_HTTP_PORT);
  272. }
  273. }
  274. else
  275. {
  276. pRequest->SetHostPort(hostPort);
  277. }
  278. //
  279. // if the object name is not set then all cache methods fail
  280. //
  281. URLGEN_FUNC fn;
  282. fn = (URLGEN_FUNC)pHttpGetUrlString;
  283. //
  284. // BUGBUG - change prototype to take LPCSTR
  285. //
  286. error = pRequest->SetObjectName((LPSTR)lpszObjectName,
  287. NULL,
  288. &fn
  289. );
  290. quit:
  291. _InternetDecNestingCount(1);
  292. done:
  293. if (error != ERROR_SUCCESS) {
  294. if (hRequest != NULL) {
  295. WinHttpCloseHandle(((HANDLE_OBJECT *)hRequest)->GetPseudoHandle());
  296. }
  297. DEBUG_ERROR(HTTP, error);
  298. SetLastError(error);
  299. hRequest = NULL;
  300. } else {
  301. //
  302. // success - don't return the object address, return the pseudo-handle
  303. // value we generated
  304. //
  305. hRequest = ((HANDLE_OBJECT *)hRequest)->GetPseudoHandle();
  306. }
  307. if (hConnectMapped != NULL) {
  308. DereferenceObject((LPVOID)hConnectMapped);
  309. }
  310. DEBUG_LEAVE_API(hRequest);
  311. return hRequest;
  312. }
  313. INTERNETAPI
  314. HINTERNET
  315. WINAPI
  316. WinHttpOpenRequest(
  317. IN HINTERNET hConnect,
  318. IN LPCWSTR lpszVerb,
  319. IN LPCWSTR lpszObjectName,
  320. IN LPCWSTR lpszVersion,
  321. IN LPCWSTR lpszReferrer OPTIONAL,
  322. IN LPCWSTR FAR * lplpszAcceptTypes OPTIONAL,
  323. IN DWORD dwFlags
  324. )
  325. /*++
  326. Routine Description:
  327. Creates a new HTTP request handle and stores the specified parameters
  328. in that context.
  329. Arguments:
  330. hHttpSession - An open Internet handle returned by InternetConnect()
  331. lpszVerb - The verb to use in the request
  332. lpszObjectName - The target object for the specified verb. This is
  333. typically a file name, an executable module, or a
  334. search specifier
  335. lpszVersion - The version string for the request
  336. lpszReferrer - Specifies the address (URI) of the document from
  337. which the URI in the request (lpszObjectName) was
  338. obtained. May be NULL in which case no referer is
  339. specified
  340. lplpszAcceptTypes - Points to a NULL-terminated array of LPCTSTR pointers
  341. to content-types accepted by the client. This value
  342. may be NULL in which case the default content-type
  343. (text/html) is used
  344. dwFlags - open options
  345. BUGBUG: WHAT IS THE DEFAULT CONTENT-TRANSFER-ENCODING?
  346. Return Value:
  347. !NULL - An open handle to an HTTP request.
  348. NULL - The operation failed. Error status is available by calling
  349. GetLastError().
  350. Comments:
  351. --*/
  352. {
  353. DEBUG_ENTER_API((DBG_API,
  354. Handle,
  355. "WinHttpOpenRequest",
  356. "%#x, %.80wq, %.80wq, %.80wq, %.80wq, %#x, %#08x",
  357. hConnect,
  358. lpszVerb,
  359. lpszObjectName,
  360. lpszVersion,
  361. lpszReferrer,
  362. lplpszAcceptTypes,
  363. dwFlags
  364. ));
  365. HINTERNET hConnectMapped = NULL;
  366. INTERNET_CONNECT_HANDLE_OBJECT * pConnect;
  367. DWORD dwErr = ERROR_SUCCESS;
  368. HINTERNET hInternet = NULL;
  369. MEMORYPACKET mpVerb, mpObjectName, mpVersion, mpReferrer;
  370. MEMORYPACKETTABLE mptAcceptTypes;
  371. BOOL isLocal;
  372. BOOL isAsync;
  373. if (dwFlags &~ (WINHTTP_OPEN_REQUEST_FLAGS_MASK))
  374. {
  375. dwErr = ERROR_INVALID_PARAMETER;
  376. goto cleanup;
  377. }
  378. // map the handle
  379. dwErr = MapHandleToAddress(hConnect, (LPVOID *)&hConnectMapped, FALSE);
  380. if (dwErr != ERROR_SUCCESS)
  381. {
  382. goto cleanup;
  383. }
  384. // find path from internet handle and validate handle
  385. dwErr = RIsHandleLocal(hConnectMapped,
  386. &isLocal,
  387. &isAsync,
  388. TypeHttpConnectHandle
  389. );
  390. if (dwErr != ERROR_SUCCESS)
  391. {
  392. goto cleanup;
  393. }
  394. if (lpszVerb)
  395. {
  396. if (IsBadStringPtrW(lpszVerb, -1))
  397. {
  398. dwErr = ERROR_INVALID_PARAMETER;
  399. goto cleanup;
  400. }
  401. ALLOC_MB(lpszVerb,0,mpVerb);
  402. if (!mpVerb.psStr)
  403. {
  404. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  405. goto cleanup;
  406. }
  407. UNICODE_TO_ANSI(lpszVerb,mpVerb);
  408. }
  409. if (lpszObjectName)
  410. {
  411. if (IsBadStringPtrW(lpszObjectName, -1))
  412. {
  413. dwErr = ERROR_INVALID_PARAMETER;
  414. goto cleanup;
  415. }
  416. pConnect = (INTERNET_CONNECT_HANDLE_OBJECT*)hConnectMapped;
  417. DWORD dwCodePage = pConnect->GetCodePage();
  418. dwErr = ConvertUnicodeToMultiByte(lpszObjectName, dwCodePage, &mpObjectName,
  419. (dwFlags&(WINHTTP_FLAG_ESCAPE_PERCENT|WINHTTP_FLAG_NULL_CODEPAGE))|WINHTTP_FLAG_DEFAULT_ESCAPE );
  420. if (dwErr != ERROR_SUCCESS)
  421. {
  422. goto cleanup;
  423. }
  424. }
  425. if (lpszVersion)
  426. {
  427. if (IsBadStringPtrW(lpszVersion, -1))
  428. {
  429. dwErr = ERROR_INVALID_PARAMETER;
  430. goto cleanup;
  431. }
  432. ALLOC_MB(lpszVersion,0,mpVersion);
  433. if (!mpVersion.psStr)
  434. {
  435. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  436. goto cleanup;
  437. }
  438. UNICODE_TO_ANSI(lpszVersion,mpVersion);
  439. }
  440. if (lpszReferrer)
  441. {
  442. if (IsBadStringPtrW(lpszReferrer, -1))
  443. {
  444. dwErr = ERROR_INVALID_PARAMETER;
  445. goto cleanup;
  446. }
  447. ALLOC_MB(lpszReferrer,0,mpReferrer);
  448. if (!mpReferrer.psStr)
  449. {
  450. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  451. goto cleanup;
  452. }
  453. UNICODE_TO_ANSI(lpszReferrer,mpReferrer);
  454. }
  455. // Create a table of ansi strings
  456. if (lplpszAcceptTypes)
  457. {
  458. WORD csTmp=0;
  459. do
  460. {
  461. if (IsBadReadPtr(lplpszAcceptTypes+csTmp*sizeof(LPCWSTR), sizeof(LPCWSTR)))
  462. {
  463. dwErr = ERROR_INVALID_PARAMETER;
  464. goto cleanup;
  465. }
  466. if (lplpszAcceptTypes[csTmp])
  467. {
  468. if (IsBadStringPtrW(lplpszAcceptTypes[csTmp++], -1))
  469. {
  470. dwErr = ERROR_INVALID_PARAMETER;
  471. goto cleanup;
  472. }
  473. }
  474. else
  475. break;
  476. }
  477. while (TRUE);
  478. mptAcceptTypes.SetUpFor(csTmp);
  479. for (WORD ce=0; ce < csTmp; ce++)
  480. {
  481. mptAcceptTypes.pdwAlloc[ce] = (lstrlenW(lplpszAcceptTypes[ce]) + 1)*sizeof(WCHAR);
  482. mptAcceptTypes.ppsStr[ce] = (LPSTR)ALLOC_BYTES(mptAcceptTypes.pdwAlloc[ce]*sizeof(CHAR));
  483. if (!mptAcceptTypes.ppsStr[ce])
  484. {
  485. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  486. goto cleanup;
  487. }
  488. mptAcceptTypes.pdwSize[ce] = WideCharToMultiByte(CP_ACP,
  489. 0,
  490. lplpszAcceptTypes[ce],
  491. mptAcceptTypes.pdwAlloc[ce]/sizeof(WCHAR),
  492. mptAcceptTypes.ppsStr[ce],
  493. mptAcceptTypes.pdwAlloc[ce],NULL,NULL);
  494. }
  495. }
  496. hInternet = HttpOpenRequestA(hConnect, mpVerb.psStr, mpObjectName.psStr, mpVersion.psStr,
  497. mpReferrer.psStr, (LPCSTR*)mptAcceptTypes.ppsStr,
  498. dwFlags, NULL);
  499. cleanup:
  500. if (hConnectMapped != NULL)
  501. {
  502. DereferenceObject((LPVOID)hConnectMapped);
  503. }
  504. if (dwErr!=ERROR_SUCCESS)
  505. {
  506. SetLastError(dwErr);
  507. DEBUG_ERROR(HTTP, dwErr);
  508. }
  509. DEBUG_LEAVE_API(hInternet);
  510. return hInternet;
  511. }