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.

1036 lines
29 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. HttpOpenRequestW
  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. BOOL IsInappropriateHTTPPort (INTERNET_PORT port)
  23. /*++
  24. Routine Description:
  25. The following outgoing ports should be blocked for HTTP:
  26. 21 - FTP,25 - SMTP,110 - POP3,119 - NNTP,143 - IMAP
  27. Arguments: Port number
  28. Return Value: TRUE- Need to be blocked
  29. FALSE-Not to be blocked
  30. --*/
  31. {
  32. if (port > INTERNET_MAX_WELL_KNOWN_PORT)
  33. return FALSE;
  34. switch (port) {
  35. case INTERNET_INVALID_PORT_NUMBER:
  36. case INTERNET_DEFAULT_FTP_PORT:
  37. case INTERNET_DEFAULT_SMTP_PORT:
  38. case INTERNET_DEFAULT_POP3_PORT:
  39. case INTERNET_DEFAULT_NNTP_PORT:
  40. case INTERNET_DEFAULT_IMAP_PORT:
  41. return TRUE;
  42. default:
  43. return FALSE;
  44. }
  45. }
  46. INTERNETAPI_(HINTERNET) HttpOpenRequestA(
  47. IN HINTERNET hConnect,
  48. IN LPCSTR lpszVerb OPTIONAL,
  49. IN LPCSTR lpszObjectName OPTIONAL,
  50. IN LPCSTR lpszVersion OPTIONAL,
  51. IN LPCSTR lpszReferrer OPTIONAL,
  52. IN LPCSTR FAR * lplpszAcceptTypes OPTIONAL,
  53. IN DWORD dwFlags,
  54. IN DWORD_PTR dwContext
  55. )
  56. /*++
  57. Routine Description:
  58. Creates a new HTTP request handle and stores the specified parameters
  59. in that context.
  60. Arguments:
  61. hConnect - An open Internet handle returned by InternetConnect()
  62. lpszVerb - The verb to use in the request. May be NULL in which
  63. case "GET" will be used
  64. lpszObjectName - The target object for the specified verb. This is
  65. typically a file name, an executable module, or a
  66. search specifier. May be NULL in which case the empty
  67. string will be used
  68. lpszVersion - The version string for the request. May be NULL in
  69. which case "HTTP/1.0" will be used
  70. lpszReferrer - Specifies the address (URI) of the document from
  71. which the URI in the request (lpszObjectName) was
  72. obtained. May be NULL in which case no referer is
  73. specified
  74. lplpszAcceptTypes - Points to a NULL-terminated array of LPCTSTR pointers
  75. to content-types accepted by the client. This value
  76. may be NULL in which case the default content-type
  77. (text/html) is used
  78. dwFlags - open options
  79. dwContext - app-supplied context value for call-backs
  80. BUGBUG: WHAT IS THE DEFAULT CONTENT-TRANSFER-ENCODING?
  81. Return Value:
  82. HINTERNET
  83. Success - non-NULL (open) handle to an HTTP request
  84. Failure - NULL. Error status is available by calling GetLastError()
  85. --*/
  86. {
  87. DEBUG_ENTER_API((DBG_API,
  88. Handle,
  89. "HttpOpenRequestA",
  90. "%#x, %.80q, %.80q, %.80q, %.80q, %#x, %#08x, %#08x",
  91. hConnect,
  92. lpszVerb,
  93. lpszObjectName,
  94. lpszVersion,
  95. lpszReferrer,
  96. lplpszAcceptTypes,
  97. dwFlags,
  98. dwContext
  99. ));
  100. DWORD error;
  101. HINTERNET hConnectMapped = NULL;
  102. BOOL fRequestUsingProxy;
  103. HINTERNET hRequest = NULL;
  104. if (!GlobalDataInitialized) {
  105. error = ERROR_INTERNET_NOT_INITIALIZED;
  106. goto done;
  107. }
  108. //
  109. // get the per-thread info
  110. //
  111. LPINTERNET_THREAD_INFO lpThreadInfo;
  112. lpThreadInfo = InternetGetThreadInfo();
  113. if (lpThreadInfo == NULL) {
  114. error = ERROR_INTERNET_INTERNAL_ERROR;
  115. goto done;
  116. }
  117. _InternetIncNestingCount();
  118. //
  119. // map the handle
  120. //
  121. error = MapHandleToAddress(hConnect, (LPVOID *)&hConnectMapped, FALSE);
  122. if (error != ERROR_SUCCESS) {
  123. goto quit;
  124. }
  125. //
  126. // find path from internet handle and validate handle
  127. //
  128. BOOL isLocal;
  129. BOOL isAsync;
  130. error = RIsHandleLocal(hConnectMapped,
  131. &isLocal,
  132. &isAsync,
  133. TypeHttpConnectHandle
  134. );
  135. if (error != ERROR_SUCCESS) {
  136. goto quit;
  137. }
  138. //
  139. // validate parameters. Allow lpszVerb to default to "GET" if a NULL pointer
  140. // is supplied
  141. //
  142. if (!ARGUMENT_PRESENT(lpszVerb) || (*lpszVerb == '\0')) {
  143. lpszVerb = DEFAULT_HTTP_REQUEST_VERB;
  144. }
  145. //
  146. // if a NULL pointer or empty string is supplied for the object name, then
  147. // convert to the default object name (root object)
  148. //
  149. if (!ARGUMENT_PRESENT(lpszObjectName) || (*lpszObjectName == '\0')) {
  150. lpszObjectName = "/";
  151. }
  152. //
  153. // check the rest of the parameters
  154. //
  155. if (dwFlags & ~INTERNET_FLAGS_MASK) {
  156. error = ERROR_INVALID_PARAMETER;
  157. goto quit;
  158. }
  159. //
  160. // default to the current supported version
  161. //
  162. char versionBuffer[sizeof("HTTP/4294967295.4294967295")];
  163. DWORD verMajor;
  164. DWORD verMinor;
  165. if (!ARGUMENT_PRESENT(lpszVersion) || (*lpszVersion == '\0')) {
  166. wsprintf(versionBuffer,
  167. "HTTP/%d.%d",
  168. HttpVersionInfo.dwMajorVersion,
  169. HttpVersionInfo.dwMinorVersion
  170. );
  171. lpszVersion = versionBuffer;
  172. verMajor = HttpVersionInfo.dwMajorVersion;
  173. verMinor = HttpVersionInfo.dwMinorVersion;
  174. } else if (strnicmp(lpszVersion, "HTTP/", sizeof("HTTP/") - 1) == 0) {
  175. LPSTR p = (LPSTR)lpszVersion + sizeof("HTTP/") - 1;
  176. ExtractInt(&p, 0, (LPINT)&verMajor);
  177. while (!isdigit(*p) && (*p != '\0')) {
  178. ++p;
  179. }
  180. ExtractInt(&p, 0, (LPINT)&verMinor);
  181. } else {
  182. verMajor = 1;
  183. verMinor = 0;
  184. }
  185. //
  186. // if we have HTTP 1.1 enabled in the registry and the version is < 1.1
  187. // then convert
  188. //
  189. if (GlobalEnableHttp1_1
  190. && (((verMajor == 1) && (verMinor == 0)) || (verMajor < 1))) {
  191. lpszVersion = "HTTP/1.1";
  192. }
  193. //
  194. // allow empty strings to be equivalent to NULL pointer
  195. //
  196. if (ARGUMENT_PRESENT(lpszReferrer) && (*lpszReferrer == '\0')) {
  197. lpszReferrer = NULL;
  198. }
  199. //
  200. // if the caller has specified CERN proxy access then we convert the
  201. // object request to the URL that the CERN proxy will use
  202. //
  203. INTERNET_CONNECT_HANDLE_OBJECT * pConnect;
  204. INTERNET_HANDLE_OBJECT * pInternet;
  205. LPSTR hostName;
  206. DWORD hostNameLength;
  207. INTERNET_PORT hostPort;
  208. BOOL isProxy;
  209. INTERNET_SCHEME schemeType;
  210. BOOL bSchemeChanged;
  211. pConnect = (INTERNET_CONNECT_HANDLE_OBJECT *)hConnectMapped;
  212. pInternet = (INTERNET_HANDLE_OBJECT *)pConnect->GetParent();
  213. INET_ASSERT(pInternet != NULL);
  214. INET_ASSERT(pInternet->IsValid(TypeInternetHandle) == ERROR_SUCCESS);
  215. hostName = pConnect->GetHostName(&hostNameLength);
  216. hostPort = pConnect->GetHostPort();
  217. isProxy = pConnect->GetServerInfo()->IsCernProxy();
  218. schemeType = pConnect->GetSchemeType();
  219. // WinSe Bug 21109- Security: Block http access to ports: 21, 25, 110, 119 and 143
  220. if(schemeType == INTERNET_SCHEME_HTTP && IsInappropriateHTTPPort(hostPort))
  221. {
  222. error = ERROR_INTERNET_INVALID_URL;
  223. goto quit;
  224. }
  225. //
  226. // set the per-thread info: parent handle object and context value
  227. //
  228. _InternetSetObjectHandle(lpThreadInfo, hConnect, hConnectMapped);
  229. _InternetSetContext(lpThreadInfo, dwContext);
  230. //
  231. // make local HTTP request handle object before we can add headers to it
  232. //
  233. error = RMakeHttpReqObjectHandle(hConnectMapped,
  234. &hRequest,
  235. NULL, // (CLOSE_HANDLE_FUNC)wHttpCloseRequest
  236. dwFlags,
  237. dwContext
  238. );
  239. if (error != ERROR_SUCCESS) {
  240. goto quit;
  241. }
  242. //
  243. // if the scheme type changed and we are going via proxy, get the SERVER_INFO
  244. // for the new proxy (if we changed it). N.B. We ONLY change the proxy for
  245. // this request object, NOT for the connect object
  246. //
  247. //if (isProxy && bSchemeChanged) {
  248. // ((HTTP_REQUEST_HANDLE_OBJECT *)hRequest)->SetServerInfo(schemeType);
  249. //}
  250. HTTP_REQUEST_HANDLE_OBJECT * pRequest;
  251. pRequest = (HTTP_REQUEST_HANDLE_OBJECT *)hRequest;
  252. //
  253. // add the request line
  254. //
  255. INET_ASSERT((lpszVerb != NULL) && (*lpszVerb != '\0'));
  256. INET_ASSERT((lpszObjectName != NULL) && (*lpszObjectName != '\0'));
  257. INET_ASSERT((lpszVersion != NULL) && (*lpszVersion != '\0'));
  258. pRequest->LockHeaders();
  259. //
  260. // encode the URL-path
  261. //
  262. error = pRequest->AddRequest((LPSTR)lpszVerb,
  263. (LPSTR)lpszObjectName,
  264. (LPSTR)lpszVersion
  265. );
  266. if (error != ERROR_SUCCESS) {
  267. pRequest->UnlockHeaders();
  268. goto quit;
  269. }
  270. //
  271. // set the method type from the verb
  272. //
  273. pRequest->SetMethodType(lpszVerb);
  274. //
  275. // add the headers
  276. //
  277. if (lpszReferrer != NULL) {
  278. error = pRequest->AddRequestHeader(HTTP_QUERY_REFERER,
  279. (LPSTR)lpszReferrer,
  280. lstrlen(lpszReferrer),
  281. 0,
  282. CLEAN_HEADER
  283. );
  284. if (error != ERROR_SUCCESS) {
  285. pRequest->UnlockHeaders();
  286. goto quit;
  287. }
  288. }
  289. if (lplpszAcceptTypes != NULL) {
  290. while (*lplpszAcceptTypes) {
  291. error = pRequest->AddRequestHeader(HTTP_QUERY_ACCEPT,
  292. (LPSTR)*lplpszAcceptTypes,
  293. lstrlen(*(LPSTR*)lplpszAcceptTypes),
  294. 0,
  295. CLEAN_HEADER | COALESCE_HEADER_WITH_COMMA
  296. );
  297. if (error != ERROR_SUCCESS) {
  298. pRequest->UnlockHeaders();
  299. goto quit;
  300. }
  301. ++lplpszAcceptTypes;
  302. }
  303. }
  304. INET_ASSERT(error == ERROR_SUCCESS);
  305. pRequest->UnlockHeaders();
  306. //
  307. // change the object state to opened
  308. //
  309. pRequest->SetState(HttpRequestStateOpen);
  310. ((HTTP_REQUEST_HANDLE_OBJECT *)hRequest)->SetRequestUsingProxy(
  311. FALSE
  312. );
  313. switch (pRequest->GetMethodType()) {
  314. case HTTP_METHOD_TYPE_GET:
  315. case HTTP_METHOD_TYPE_POST:
  316. break;
  317. default:
  318. dwFlags |= (INTERNET_FLAG_RELOAD | INTERNET_FLAG_NO_CACHE_WRITE);
  319. break;
  320. }
  321. switch (GlobalCacheMode)
  322. {
  323. case CACHEMODE_REFRESH:
  324. dwFlags |= INTERNET_FLAG_RESYNCHRONIZE;
  325. break;
  326. case CACHEMODE_BYPASS:
  327. dwFlags |= INTERNET_FLAG_RELOAD;
  328. break;
  329. case CACHEMODE_NORMAL:
  330. default:
  331. break;
  332. }
  333. pRequest->SetCacheFlags(dwFlags);
  334. //
  335. // if the object name is not set then all cache methods fail
  336. //
  337. URLGEN_FUNC fn;
  338. fn = (URLGEN_FUNC)pHttpGetUrlString;
  339. //
  340. // BUGBUG - change prototype to take LPCSTR
  341. //
  342. error = pRequest->SetObjectName((LPSTR)lpszObjectName,
  343. NULL,
  344. &fn
  345. );
  346. //
  347. // Record whether the original object was empty ("") or slash ("/")
  348. //
  349. if (lpszObjectName[0] == '/' &&
  350. lpszObjectName[1] == 0x00 ) {
  351. pRequest->SetObjectRoot();
  352. }
  353. quit:
  354. _InternetDecNestingCount(1);
  355. done:
  356. if (error != ERROR_SUCCESS) {
  357. if (hRequest != NULL) {
  358. InternetCloseHandle(((HANDLE_OBJECT *)hRequest)->GetPseudoHandle());
  359. }
  360. DEBUG_ERROR(HTTP, error);
  361. SetLastError(error);
  362. hRequest = NULL;
  363. } else {
  364. //
  365. // success - don't return the object address, return the pseudo-handle
  366. // value we generated
  367. //
  368. hRequest = ((HANDLE_OBJECT *)hRequest)->GetPseudoHandle();
  369. }
  370. if (hConnectMapped != NULL) {
  371. DereferenceObject((LPVOID)hConnectMapped);
  372. }
  373. DEBUG_LEAVE_API(hRequest);
  374. return hRequest;
  375. }
  376. INTERNETAPI_(HINTERNET) HttpOpenRequestW(
  377. IN HINTERNET hConnect,
  378. IN LPCWSTR lpszVerb,
  379. IN LPCWSTR lpszObjectName,
  380. IN LPCWSTR lpszVersion,
  381. IN LPCWSTR lpszReferrer OPTIONAL,
  382. IN LPCWSTR FAR * lplpszAcceptTypes OPTIONAL,
  383. IN DWORD dwFlags,
  384. IN DWORD_PTR dwContext
  385. )
  386. /*++
  387. Routine Description:
  388. Creates a new HTTP request handle and stores the specified parameters
  389. in that context.
  390. Arguments:
  391. hHttpSession - An open Internet handle returned by InternetConnect()
  392. lpszVerb - The verb to use in the request
  393. lpszObjectName - The target object for the specified verb. This is
  394. typically a file name, an executable module, or a
  395. search specifier
  396. lpszVersion - The version string for the request
  397. lpszReferrer - Specifies the address (URI) of the document from
  398. which the URI in the request (lpszObjectName) was
  399. obtained. May be NULL in which case no referer is
  400. specified
  401. lplpszAcceptTypes - Points to a NULL-terminated array of LPCTSTR pointers
  402. to content-types accepted by the client. This value
  403. may be NULL in which case the default content-type
  404. (text/html) is used
  405. dwFlags - open options
  406. dwContext - app-supplied context value for call-backs
  407. BUGBUG: WHAT IS THE DEFAULT CONTENT-TRANSFER-ENCODING?
  408. Return Value:
  409. !NULL - An open handle to an HTTP request.
  410. NULL - The operation failed. Error status is available by calling
  411. GetLastError().
  412. Comments:
  413. --*/
  414. {
  415. DEBUG_ENTER_API((DBG_API,
  416. Handle,
  417. "HttpOpenRequestW",
  418. "%#x, %.80wq, %.80wq, %.80wq, %.80wq, %#x, %#08x, %#08x",
  419. hConnect,
  420. lpszVerb,
  421. lpszObjectName,
  422. lpszVersion,
  423. lpszReferrer,
  424. lplpszAcceptTypes,
  425. dwFlags,
  426. dwContext
  427. ));
  428. DWORD dwErr = ERROR_SUCCESS;
  429. HINTERNET hInternet = NULL;
  430. MEMORYPACKET mpVerb, mpObjectName, mpVersion, mpReferrer;
  431. MEMORYPACKETTABLE mptAcceptTypes;
  432. if (lpszVerb)
  433. {
  434. ALLOC_MB(lpszVerb,0,mpVerb);
  435. if (!mpVerb.psStr)
  436. {
  437. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  438. goto cleanup;
  439. }
  440. UNICODE_TO_ANSI(lpszVerb,mpVerb);
  441. }
  442. if (lpszObjectName)
  443. {
  444. ALLOC_MB(lpszObjectName,0,mpObjectName);
  445. if (!mpObjectName.psStr)
  446. {
  447. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  448. goto cleanup;
  449. }
  450. UNICODE_TO_ANSI(lpszObjectName,mpObjectName);
  451. }
  452. if (lpszVersion)
  453. {
  454. ALLOC_MB(lpszVersion,0,mpVersion);
  455. if (!mpVersion.psStr)
  456. {
  457. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  458. goto cleanup;
  459. }
  460. UNICODE_TO_ANSI(lpszVersion,mpVersion);
  461. }
  462. if (lpszReferrer)
  463. {
  464. ALLOC_MB(lpszReferrer,0,mpReferrer);
  465. if (!mpReferrer.psStr)
  466. {
  467. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  468. goto cleanup;
  469. }
  470. UNICODE_TO_ANSI(lpszReferrer,mpReferrer);
  471. }
  472. // Create a table of ansi strings
  473. if (lplpszAcceptTypes)
  474. {
  475. WORD csTmp=0;
  476. for (;lplpszAcceptTypes[csTmp];csTmp++);
  477. mptAcceptTypes.SetUpFor(csTmp);
  478. for (WORD ce=0; ce < csTmp; ce++)
  479. {
  480. mptAcceptTypes.pdwAlloc[ce] = (lstrlenW(lplpszAcceptTypes[ce]) + 1)*sizeof(WCHAR);
  481. mptAcceptTypes.ppsStr[ce] = (LPSTR)ALLOC_BYTES(mptAcceptTypes.pdwAlloc[ce]*sizeof(CHAR));
  482. if (!mptAcceptTypes.ppsStr[ce])
  483. {
  484. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  485. goto cleanup;
  486. }
  487. mptAcceptTypes.pdwSize[ce] = WideCharToMultiByte(CP_ACP,
  488. 0,
  489. lplpszAcceptTypes[ce],
  490. mptAcceptTypes.pdwAlloc[ce]/sizeof(WCHAR),
  491. mptAcceptTypes.ppsStr[ce],
  492. mptAcceptTypes.pdwAlloc[ce],NULL,NULL);
  493. }
  494. }
  495. hInternet = HttpOpenRequestA(hConnect, mpVerb.psStr, mpObjectName.psStr, mpVersion.psStr,
  496. mpReferrer.psStr, (LPCSTR*)mptAcceptTypes.ppsStr,
  497. dwFlags, dwContext);
  498. cleanup:
  499. if (dwErr!=ERROR_SUCCESS)
  500. {
  501. SetLastError(dwErr);
  502. DEBUG_ERROR(HTTP, dwErr);
  503. }
  504. DEBUG_LEAVE_API(hInternet);
  505. return hInternet;
  506. }
  507. DWORD
  508. ParseHttpUrl(
  509. IN OUT LPHINTERNET phInternet,
  510. IN LPSTR lpszUrl,
  511. IN DWORD dwSchemeLength,
  512. IN LPSTR lpszHeaders,
  513. IN DWORD dwHeadersLength,
  514. IN DWORD dwFlags,
  515. IN DWORD_PTR dwContext
  516. )
  517. /*++
  518. Routine Description:
  519. URL parser for HTTP URLs. Support function for InternetOpenUrl() and
  520. ParseUrl().
  521. This is a macro function that just cracks the URL and calls HTTP APIs to
  522. do the work
  523. Arguments:
  524. phInternet - IN: InternetOpen() handle
  525. OUT: if successful HttpOpenRequest(), else undefined
  526. lpszUrl - pointer to string containing HTTP URL to open
  527. dwSchemeLength - length of the URL scheme, exluding "://"
  528. lpszHeaders - additional HTTP headers
  529. dwHeadersLength - length of Headers
  530. dwFlags - optional flags for opening a file (cache/no-cache, etc.)
  531. dwContext - context value for callbacks
  532. Return Value:
  533. DWORD
  534. Success - ERROR_SUCCESS
  535. Failure - ERROR_INTERNET_INVALID_URL
  536. The URL passed in could not be parsed
  537. --*/
  538. {
  539. DEBUG_ENTER((DBG_HTTP,
  540. Dword,
  541. "ParseHttpUrl",
  542. "%#x [%#x], %q, %d, %.80q, %d, %08x, %08x",
  543. phInternet,
  544. *phInternet,
  545. lpszUrl,
  546. dwSchemeLength,
  547. lpszHeaders,
  548. dwHeadersLength,
  549. dwFlags,
  550. dwContext
  551. ));
  552. INET_ASSERT(GlobalDataInitialized);
  553. DWORD error = DoFsm(new CFsm_ParseHttpUrl(phInternet,
  554. lpszUrl,
  555. dwSchemeLength,
  556. lpszHeaders,
  557. dwHeadersLength,
  558. dwFlags,
  559. dwContext
  560. ));
  561. DEBUG_LEAVE(error);
  562. return error;
  563. }
  564. DWORD
  565. ParseHttpUrl_Fsm(
  566. IN CFsm_ParseHttpUrl * Fsm
  567. )
  568. /*++
  569. Routine Description:
  570. Run next ParseHttpUrl state. Note this FSM has no RunSM(). Since there is
  571. no object to instantiate, we don't need one
  572. Arguments:
  573. Fsm - pointer to FSM controlling operation
  574. Return Value:
  575. DWORD
  576. Success - ERROR_SUCCESS
  577. ERROR_IO_PENDING
  578. Failure -
  579. --*/
  580. {
  581. DEBUG_ENTER((DBG_HTTP,
  582. Dword,
  583. "ParseHttpUrl_Fsm",
  584. "%#x",
  585. Fsm
  586. ));
  587. CFsm_ParseHttpUrl & fsm = *Fsm;
  588. DWORD error = fsm.GetError();
  589. BOOL success;
  590. if (fsm.IsInvalid()) {
  591. goto quit;
  592. }
  593. if (fsm.GetState() == FSM_STATE_CONTINUE) {
  594. goto parse_continue;
  595. }
  596. LPSTR userName;
  597. DWORD userNameLength;
  598. LPSTR password;
  599. DWORD passwordLength;
  600. LPSTR pHostName;
  601. DWORD hostNameLength;
  602. DWORD urlLength;
  603. INTERNET_PORT port;
  604. LPSTR schemeName;
  605. //
  606. // new scheme - we now pass in the entire URL, so find the start of the
  607. // address info again. Keep a pointer to the scheme (may be different than
  608. // http:// if going via proxy); we already know the scheme length from the
  609. // parameters
  610. //
  611. schemeName = fsm.m_lpszUrl;
  612. fsm.m_lpszUrl += fsm.m_dwSchemeLength + sizeof("://") - 1;
  613. //
  614. // extract the address information - no user name or password
  615. //
  616. error = GetUrlAddress(&fsm.m_lpszUrl,
  617. &urlLength,
  618. &userName,
  619. &userNameLength,
  620. &password,
  621. &passwordLength,
  622. &pHostName,
  623. &hostNameLength,
  624. &port,
  625. NULL
  626. );
  627. if (error != ERROR_SUCCESS) {
  628. goto quit;
  629. }
  630. //
  631. // if we got user name & password, convert them to zero-terminated strings.
  632. // The URL is a copy, so we can write into it, and the characters that
  633. // terminate user name & password (@ & : resp) are not significant
  634. //
  635. if (userName != NULL) {
  636. userName[userNameLength] = '\0';
  637. }
  638. if (password != NULL) {
  639. password[passwordLength] = '\0';
  640. }
  641. //
  642. // get the HTTP object path - decode any escape sequences
  643. //
  644. //if (*Url != '\0') {
  645. //
  646. // INET_ASSERT((int)urlLength > 0);
  647. //
  648. // error = DecodeUrlStringInSitu(Url, &urlLength);
  649. // if (error != ERROR_SUCCESS) {
  650. // goto quit;
  651. // }
  652. //}
  653. //
  654. // convert the host name pointer and length to an ASCIIZ string
  655. //
  656. char hostName[INTERNET_MAX_HOST_NAME_LENGTH + 1];
  657. DWORD len;
  658. len = (DWORD)min(hostNameLength, sizeof(hostName) - 1);
  659. memcpy(hostName, pHostName, len);
  660. hostName[len] = '\0';
  661. //
  662. // make the GET request
  663. //
  664. HINTERNET hConnect;
  665. HINTERNET hRequest;
  666. fsm.m_hConnect = NULL;
  667. fsm.m_hRequest = NULL;
  668. //
  669. // if there is no port specified and we're sending an FTP or gopher request
  670. // then we have to map the port, or else we will try to use the HTTP port
  671. // (80)
  672. //
  673. INTERNET_SCHEME scheme;
  674. scheme = MapUrlSchemeName(schemeName, fsm.m_dwSchemeLength);
  675. if (port == INTERNET_INVALID_PORT_NUMBER) {
  676. switch (scheme) {
  677. case INTERNET_SCHEME_FTP:
  678. port = INTERNET_DEFAULT_FTP_PORT;
  679. break;
  680. case INTERNET_SCHEME_GOPHER:
  681. port = INTERNET_DEFAULT_GOPHER_PORT;
  682. break;
  683. }
  684. }
  685. fsm.m_hConnect = InternetConnect(*fsm.m_phInternet,
  686. hostName,
  687. port,
  688. userName,
  689. password,
  690. INTERNET_SERVICE_HTTP,
  691. //
  692. // we can ignore EXISTING_CONNECT for HTTP
  693. // connect handle objects
  694. //
  695. fsm.m_dwFlags & ~INTERNET_FLAG_EXISTING_CONNECT,
  696. //
  697. // we are creating a "hidden" handle - don't
  698. // tell the app about it
  699. //
  700. INTERNET_NO_CALLBACK
  701. );
  702. if (fsm.m_hConnect != NULL) {
  703. //
  704. // set the real scheme type. e.g. we may be performing a CERN proxy
  705. // request for an FTP site, in which case the real scheme type is FTP
  706. //
  707. HINTERNET hConnectMapped;
  708. error = MapHandleToAddress(fsm.m_hConnect, (LPVOID *)&hConnectMapped, FALSE);
  709. if (error != ERROR_SUCCESS) {
  710. goto quit;
  711. }
  712. ((INTERNET_CONNECT_HANDLE_OBJECT *)hConnectMapped)->SetSchemeType(scheme);
  713. DereferenceObject((LPVOID)hConnectMapped);
  714. //
  715. // create the request object. Both proxy and non-proxy paths submit only
  716. // the URL-path
  717. //
  718. //
  719. // BUGBUG - this should be fixed in java download code!
  720. //
  721. // java downloads (synchronous) are requesting INTERNET_FLAG_EXISTING_CONNECT
  722. // when they really want INTERNET_FLAG_KEEP_CONNECTION
  723. //
  724. if (fsm.m_dwFlags & INTERNET_FLAG_EXISTING_CONNECT) {
  725. fsm.m_dwFlags |= INTERNET_FLAG_KEEP_CONNECTION;
  726. }
  727. fsm.m_hRequest = HttpOpenRequest(fsm.m_hConnect,
  728. NULL, // default verb is GET
  729. fsm.m_lpszUrl,
  730. NULL, // default version is HTTP/1.0
  731. NULL, // default referrer
  732. NULL, // default accept encodings
  733. fsm.m_dwFlags,
  734. fsm.m_dwContext
  735. );
  736. if (fsm.m_hRequest != NULL) {
  737. success = HttpSendRequest(fsm.m_hRequest,
  738. fsm.m_lpszHeaders,
  739. fsm.m_dwHeadersLength,
  740. NULL,
  741. 0
  742. );
  743. if (!success) {
  744. error = GetLastError();
  745. if (error == ERROR_IO_PENDING) {
  746. goto quit;
  747. parse_continue:
  748. //
  749. // in the async case, the result from HttpSendRequest() is
  750. // returned as a DWORD error. Convert it back to a BOOL
  751. //
  752. success = (BOOL)(error == ERROR_SUCCESS);
  753. }
  754. }
  755. }
  756. } else {
  757. error = GetLastError();
  758. }
  759. if (success) {
  760. //
  761. // associate the connect handle with the request handle, so that when
  762. // we close the request handle, the connect handle is also closed
  763. //
  764. HINTERNET hConnectMapped = NULL;
  765. HINTERNET hRequestMapped = NULL;
  766. error = MapHandleToAddress(fsm.m_hConnect, (LPVOID *)&hConnectMapped, FALSE);
  767. if (error == ERROR_SUCCESS) {
  768. error = MapHandleToAddress(fsm.m_hRequest, (LPVOID *)&hRequestMapped, FALSE);
  769. if (error == ERROR_SUCCESS) {
  770. RSetParentHandle(hRequestMapped, hConnectMapped, TRUE);
  771. //
  772. // return the request handle
  773. //
  774. DEBUG_PRINT(HTTP,
  775. INFO,
  776. ("returning handle %#x\n",
  777. fsm.m_hRequest
  778. ));
  779. *fsm.m_phInternet = fsm.m_hRequest;
  780. }
  781. }
  782. //
  783. // dereference the handles referenced by MapHandleToAddress()
  784. //
  785. if (hRequestMapped != NULL) {
  786. DereferenceObject((LPVOID)hRequestMapped);
  787. }
  788. if (hConnectMapped != NULL) {
  789. DereferenceObject((LPVOID)hConnectMapped);
  790. }
  791. }
  792. quit:
  793. if ((error != ERROR_SUCCESS) && (error != ERROR_IO_PENDING)) {
  794. if (fsm.m_hRequest != NULL) {
  795. InternetCloseHandle(fsm.m_hRequest);
  796. }
  797. if (fsm.m_hConnect != NULL) {
  798. InternetCloseHandle(fsm.m_hConnect);
  799. }
  800. }
  801. if (error != ERROR_IO_PENDING) {
  802. fsm.SetDone();
  803. }
  804. DEBUG_LEAVE(error);
  805. return error;
  806. }