Remove unused ProjectConfiguration
[xy_vsfilter.git] / include / atl / atlhttp.inl
blob71294b49b8ebfb2847e5798ba358b4f5b94800dc
1 // This is a part of the Active Template Library.\r
2 // Copyright (C) Microsoft Corporation\r
3 // All rights reserved.\r
4 //\r
5 // This source code is only intended as a supplement to the\r
6 // Active Template Library Reference and related\r
7 // electronic documentation provided with the library.\r
8 // See these sources for detailed information regarding the\r
9 // Active Template Library product.\r
11 #ifndef __ATLHTTP_INL__\r
12 #define __ATLHTTP_INL__\r
14 #include <errno.h>\r
16 #pragma warning(push)\r
17 #pragma warning(disable: 4061) // enumerate 'enum value' in switch of enum 'enum type' is not explicitly handled by a case label\r
18 #pragma warning(disable: 4062) // enumerate 'enum value' in switch of enum 'enum type' is not handled\r
20 namespace ATL\r
21 {\r
23 /////////////////////////////////////////////////////////////////////////////////\r
24 //\r
25 // CAtlHttpClient\r
26 // Implementation of CAtlHttpClient member functions\r
27 //\r
28 /////////////////////////////////////////////////////////////////////////////////\r
29 template <class TSocketClass>\r
30 inline CAtlHttpClientT<TSocketClass>::CAtlHttpClientT() throw()\r
31 {\r
32         InitializeObject();\r
33 }\r
35 // Sets this object to a known state.\r
36 template <class TSocketClass>\r
37 inline void CAtlHttpClientT<TSocketClass>::InitializeObject() throw()\r
38 {\r
39         Close(); // will close the socket if it's already open\r
40         ResetRequest();\r
41         SetSilentLogonOk(FALSE);\r
42 }\r
44 template <class TSocketClass>\r
45 inline void CAtlHttpClientT<TSocketClass>::ResetRequest() throw()\r
46 {\r
47         // reset all data that has to do with the current request\r
48         m_HeaderMap.RemoveAll();\r
49         m_current.Empty();\r
50         m_urlCurrent.Clear();\r
51         m_strMethod.Empty();\r
52         m_nStatus = ATL_INVALID_STATUS;\r
53         m_dwBodyLen = 0;\r
54         m_dwHeaderLen = 0;\r
55         m_dwHeaderStart = 0;\r
56         m_pCurrent = NULL;\r
57         m_pNavData = NULL;\r
58         m_LastResponseParseError = RR_NOT_READ;\r
59         m_pEnd = NULL;\r
61 }\r
64 // Use this function to retrieve an entity from a server via an HTTP\r
65 // request. This function will either request a connection from the\r
66 // server specified in the szURL parameter or request a connection from\r
67 // the proxy server. If a proxy server is to be used, you must call\r
68 // SetProxy prior to calling this function to specify the proxy server\r
69 // being used. Once the connection is established, an HTTP request \r
70 // is built and sent to the HTTP server. An attempt to read the HTTP\r
71 // response is then made. If the response is successfully read, the\r
72 // response will be parsed and stored in this class instance. The \r
73 // headers can be parsed via the LookupHeader function and the body\r
74 // of the response can be retrieved using the GetBody function. You\r
75 // can also retrieve the contents of the entire response by calling\r
76 // GetResponse.\r
77 template <class TSocketClass>\r
78 inline bool CAtlHttpClientT<TSocketClass>::Navigate(\r
80                                 LPCTSTR szUrl,\r
81                                 ATL_NAVIGATE_DATA *pNavData\r
82                         ) throw(...)\r
83 {\r
84         if (!szUrl || *szUrl == _T('\0'))\r
85                 return false;\r
87         CUrl url;\r
88         TCHAR szTmp[ATL_URL_MAX_URL_LENGTH];\r
89         if(!AtlEscapeUrl(szUrl,szTmp,0,ATL_URL_MAX_URL_LENGTH-1,ATL_URL_BROWSER_MODE))\r
90                 return false;\r
92         if(!url.CrackUrl(szTmp))\r
93                 return false;\r
95         // Navigate\r
96         return Navigate(&url, pNavData);\r
97 }\r
99 template <class TSocketClass>\r
100 inline bool CAtlHttpClientT<TSocketClass>::Navigate(\r
101                         LPCTSTR szServer,\r
102                         LPCTSTR szPath, \r
103                         ATL_NAVIGATE_DATA *pNavData\r
104                         ) throw(...)\r
106         // Create a URL\r
107         if (!szServer || *szServer == _T('\0'))\r
108                 return false;\r
109         if (!szPath || *szPath == _T('\0'))\r
110                 return false;\r
111         CUrl url;\r
112         url.SetScheme(ATL_URL_SCHEME_HTTP);\r
113         url.SetHostName(szServer);\r
114         url.SetUrlPath(szPath);\r
115         if (pNavData)\r
116                 url.SetPortNumber(pNavData->nPort); \r
117         else\r
118                 url.SetPortNumber(ATL_URL_DEFAULT_HTTP_PORT);\r
120         TCHAR szUrl[ATL_URL_MAX_URL_LENGTH];\r
121         DWORD dwMaxLen = ATL_URL_MAX_URL_LENGTH;\r
122         if (!url.CreateUrl(szUrl, &dwMaxLen))\r
123                 return false;\r
125         // Navigate\r
126         return Navigate(szUrl, pNavData);\r
129 template <class TSocketClass>\r
130 inline bool CAtlHttpClientT<TSocketClass>::Navigate(\r
131                         const CUrl *pUrl,\r
132                         ATL_NAVIGATE_DATA *pData\r
133                         )  throw(...)\r
135         bool bRet = false;\r
136         if (!pUrl)\r
137                 return false;\r
139         ResetRequest();\r
140         \r
141         CAtlNavigateData default_nav_data;\r
142         if (!pData)\r
143                 m_pNavData = &default_nav_data;\r
144         else\r
145                 m_pNavData = pData;\r
147         ATLASSUME(m_pNavData);\r
149         _ATLTRY\r
150         {\r
151                 m_strMethod = m_pNavData->szMethod;\r
152         }\r
153         _ATLCATCHALL()\r
154         {\r
155                 return false;\r
156         }\r
158         SetSocketTimeout(m_pNavData->dwTimeout);\r
160         // set m_urlCurrent\r
161         if (!SetDefaultUrl(pUrl, m_pNavData->nPort))\r
162                 return false;\r
163         DWORD dwSent = 0;\r
164         CString strRequest;\r
165         CString strExtraInfo;\r
167         if (!BuildRequest(&strRequest, \r
168                                         m_pNavData->szMethod,\r
169                                         m_pNavData->szExtraHeaders))\r
170         {\r
171                 return false;\r
172         }\r
174         \r
175         if (!ConnectSocket())\r
176                 return false;\r
178         LPCTSTR szTRequest = strRequest;\r
179         CT2CA strARequest(szTRequest);\r
180         DWORD dwRequestLen = (DWORD)strlen(strARequest);\r
181         DWORD dwAvailable = dwRequestLen + m_pNavData->dwDataLen;\r
183         if (m_pNavData->dwFlags & ATL_HTTP_FLAG_SEND_CALLBACK)\r
184         {\r
185                 dwSent = WriteWithCallback(strARequest, dwRequestLen);\r
186         }\r
187         else if (!m_pNavData->pData)\r
188                 dwSent = WriteWithNoData(strARequest, dwRequestLen);\r
189         else if (m_pNavData->pData && (m_pNavData->dwFlags & ATL_HTTP_FLAG_SEND_BLOCKS))\r
190         {\r
191                 dwSent = WriteWithChunks(strARequest, dwRequestLen);\r
192         }\r
193         else if(m_pNavData->pData)\r
194         {\r
195                 dwSent = WriteWithData(strARequest, dwRequestLen);\r
196         }\r
199         // make sure everything was sent\r
200         if (dwSent == dwAvailable)\r
201         {\r
202                 // Read the response\r
203                 if (RR_OK == ReadHttpResponse())\r
204                 {\r
205                         // if navigation isn't complete, try to complete\r
206                         // it based on the status code and flags\r
207                         if ((m_pNavData->dwFlags & ATL_HTTP_FLAG_PROCESS_RESULT)&&\r
208                                 !ProcessStatus(m_pNavData->dwFlags))\r
209                         {\r
210                                 bRet = false;\r
211                         }\r
212                         else\r
213                                 bRet = true;\r
214                 }\r
215                 else\r
216                         bRet = false;\r
217         }\r
219         if (!bRet)\r
220                 Close(); // some kind of failure happened, close the socket.\r
222         m_pNavData = NULL;\r
223         return bRet;\r
226 template <class TSocketClass>\r
227 inline DWORD CAtlHttpClientT<TSocketClass>::WriteWithNoData(LPCSTR pRequest, DWORD dwRequestLen)\r
229         ATLASSUME(m_pNavData);\r
230         WSABUF Buffer;\r
231         Buffer.buf = (char*)pRequest;\r
232         Buffer.len = (int)dwRequestLen;\r
233         DWORD dwWritten = 0;\r
234         Write(&Buffer, 1, &dwWritten);\r
235         if (m_pNavData->pfnSendStatusCallback)\r
236                 m_pNavData->pfnSendStatusCallback(dwWritten, m_pNavData->m_lParamSend);\r
237         return dwWritten;\r
240 // The entity body will be retrieved from the client by calling their\r
241 // callback function.\r
242 template <class TSocketClass>\r
243 inline DWORD CAtlHttpClientT<TSocketClass>::WriteWithCallback(LPCSTR pRequest, DWORD dwRequestLen)\r
245         ATLASSUME(m_pNavData);\r
246         if (!(m_pNavData->pfnChunkCallback &&\r
247                 (m_pNavData->dwFlags & ATL_HTTP_FLAG_SEND_CALLBACK)))\r
248                 return 0; // error, must have flag set and callback function\r
250         // write the request\r
251         DWORD dwTotalWritten = 0;\r
252         WSABUF Buffer;\r
253         Buffer.buf = (char*)pRequest;\r
254         Buffer.len = (int)dwRequestLen;\r
255         DWORD dwWritten = 0;\r
256         Write(&Buffer, 1, &dwWritten);\r
257         if (m_pNavData->pfnSendStatusCallback)\r
258                 if (!m_pNavData->pfnSendStatusCallback(dwWritten, m_pNavData->m_lParamSend))\r
259                         return 0;\r
260         if (!dwWritten)\r
261                 return 0; // failure\r
262         dwTotalWritten += dwWritten;\r
264         // start writing data;\r
265         while (m_pNavData->pfnChunkCallback((BYTE**)&Buffer.buf, (DWORD*)&Buffer.len, m_pNavData->m_lParamChunkCB) &&\r
266                         Buffer.len > 0 &&\r
267                         Buffer.buf != NULL)\r
268         {\r
269                 Write(&Buffer, 1, &dwWritten);\r
270                 if (dwWritten != Buffer.len)\r
271                         return 0;\r
272                 if (m_pNavData->pfnSendStatusCallback)\r
273                         if (!m_pNavData->pfnSendStatusCallback(dwWritten, m_pNavData->m_lParamSend))\r
274                                 return 0;\r
275                 dwTotalWritten += dwWritten;\r
276         }\r
277         return dwTotalWritten;\r
280 template <class TSocketClass>\r
281 inline DWORD CAtlHttpClientT<TSocketClass>::WriteWithChunks(LPCSTR pRequest, DWORD dwRequestLen)\r
283         ATLASSUME(m_pNavData);\r
284         if (!(m_pNavData->dwSendBlockSize > 0 && (m_pNavData->dwFlags & ATL_HTTP_FLAG_SEND_BLOCKS)))\r
285                 return 0; // error, must have flag set and callback function\r
287         // write the request\r
288         DWORD dwTotalWritten = 0;\r
289         WSABUF Buffer;\r
290         Buffer.buf = (char*)pRequest;\r
291         Buffer.len = (int)dwRequestLen;\r
292         DWORD dwWritten = 0;\r
293         Write(&Buffer, 1, &dwWritten);\r
294         if (m_pNavData->pfnSendStatusCallback)\r
295                 if (!m_pNavData->pfnSendStatusCallback(dwWritten, m_pNavData->m_lParamSend))\r
296                         return 0;\r
297         if (!dwWritten)\r
298                 return 0; // failure\r
299         dwTotalWritten += dwWritten;\r
301         // start writing data;\r
302         DWORD dwDataWritten = 0;\r
303         DWORD dwDataLeft = m_pNavData->dwDataLen;\r
304         while (dwDataLeft)\r
305         {\r
306                 Buffer.buf = (char*)(m_pNavData->pData + dwDataWritten);\r
307                 Buffer.len = __min(dwDataLeft, m_pNavData->dwSendBlockSize);\r
308                 Write(&Buffer, 1, &dwWritten);\r
309                 if (dwWritten != Buffer.len)\r
310                         return 0;\r
311                 if (m_pNavData->pfnSendStatusCallback)\r
312                         if (!m_pNavData->pfnSendStatusCallback(dwWritten, m_pNavData->m_lParamSend))\r
313                                 return false;\r
314                 dwTotalWritten += dwWritten;\r
315                 dwDataWritten += dwWritten;\r
316                 dwDataLeft -= dwWritten;\r
317         }\r
318         return dwTotalWritten;\r
321 template <class TSocketClass>\r
322 inline DWORD CAtlHttpClientT<TSocketClass>::WriteWithData(LPCSTR pRequest, DWORD dwRequestLen)\r
324         WSABUF Buffers[2];\r
325         Buffers[0].buf = (char*)pRequest;\r
326         Buffers[0].len = dwRequestLen;\r
327         Buffers[1].buf = (char*)m_pNavData->pData;\r
328         Buffers[1].len = m_pNavData->dwDataLen;\r
330         DWORD dwWritten = 0;\r
331         Write(Buffers, 2, &dwWritten);\r
332         if (m_pNavData->pfnSendStatusCallback)\r
333                 m_pNavData->pfnSendStatusCallback(dwWritten, m_pNavData->m_lParamSend);\r
335         return dwWritten;\r
338 template <class TSocketClass>\r
339 bool CAtlHttpClientT<TSocketClass>::NavigateChunked(\r
340                                 LPCTSTR szServer,\r
341                                 LPCTSTR szPath,\r
342                                 ATL_NAVIGATE_DATA *pNavData\r
343                                 ) throw()\r
345         // Create a URL\r
346         if (!szServer || *szServer == _T('\0'))\r
347                 return false;\r
348         if (!szPath || *szPath == _T('\0'))\r
349                 return false;\r
351         if (!pNavData)\r
352         {\r
353                 // To do chunked navigation you must specify an\r
354                 // ATL_NAVIGATE_DATA structure that has the pfnChunkCallback\r
355                 // member filled out.\r
356                 ATLASSERT(FALSE);\r
357                 return false;\r
358         }\r
359         CUrl url;\r
360         url.SetScheme(ATL_URL_SCHEME_HTTP);\r
361         url.SetHostName(szServer);\r
362         url.SetUrlPath(szPath);\r
363         if (pNavData)\r
364                 url.SetPortNumber(pNavData->nPort); \r
365         else\r
366                 url.SetPortNumber(ATL_URL_DEFAULT_HTTP_PORT);\r
368         TCHAR szUrl[ATL_URL_MAX_URL_LENGTH];\r
369         DWORD dwMaxLen = ATL_URL_MAX_URL_LENGTH;\r
370         if (!url.CreateUrl(szUrl, &dwMaxLen))\r
371                 return false;\r
373         // Navigate\r
374         return NavigateChunked(szUrl, pNavData);\r
377 template <class TSocketClass>\r
378 bool CAtlHttpClientT<TSocketClass>::NavigateChunked(\r
379                         LPCTSTR szURL,\r
380                         ATL_NAVIGATE_DATA *pNavData\r
381                         ) throw()\r
383         if (!szURL || *szURL == _T('\0'))\r
384                 return false;\r
386         ResetRequest();\r
388         ATLASSERT(pNavData);\r
390         CUrl url;\r
391         if (!url.CrackUrl(szURL))\r
392                 return false;\r
394         // Navigate\r
395         return NavigateChunked(&url, pNavData);\r
398 template <class TSocketClass>\r
399 inline bool CAtlHttpClientT<TSocketClass>::NavigateChunked(\r
400                 const CUrl *pUrl,\r
401                 ATL_NAVIGATE_DATA *pNavData\r
402                 ) throw()\r
404         if (!pUrl)\r
405                 return false;\r
407         if (!pNavData)\r
408         {\r
409                 // To do chunked navigation you must specify an\r
410                 // ATL_NAVIGATE_DATA structure that has the pfnChunkCallback\r
411                 // member filled out.\r
412                 ATLASSERT(FALSE);\r
413                 return false;\r
414         }\r
416         m_pNavData = pNavData;\r
417         if (!pNavData->pfnChunkCallback)\r
418                 return false;\r
420         bool bRet = true;\r
421         \r
422         _ATLTRY\r
423         {\r
424                 m_strMethod = m_pNavData->szMethod;\r
425         }\r
426         _ATLCATCHALL()\r
427         {\r
428                 return false;\r
429         }\r
431         SetSocketTimeout(m_pNavData->dwTimeout);\r
433         // set m_urlCurrent\r
434         if (!SetDefaultUrl(pUrl, m_pNavData->nPort))\r
435                 return false;\r
438         DWORD dwSent = 0;\r
439         CString strRequest;\r
440         CString strExtraInfo;\r
442         if (!BuildRequest(&strRequest,\r
443                                         m_pNavData->szMethod,\r
444                                         m_pNavData->szExtraHeaders // extra headers\r
445                                         ))\r
446         {\r
447                 return false;\r
448         }\r
450         if (!ConnectSocket())\r
451                 return false;\r
453         WSABUF Buffers[3];\r
455         _ATLTRY\r
456         {\r
457                 CT2A pRequest(strRequest);\r
459                 Buffers[0].buf = (char*)pRequest;\r
460                 Buffers[0].len = strRequest.GetLength();\r
462                 // send the first buffer which is the request\r
463                 if (!Write(Buffers, 1, &dwSent))\r
464                 {\r
465                         Close();\r
466                         return false;\r
467                 }\r
468         }\r
469         _ATLCATCHALL()\r
470         {\r
471                 Close();\r
472                 return false;\r
473         }\r
474         Buffers[0].buf = NULL;\r
475         Buffers[0].len = 0;\r
477         CStringA strChunkSize;\r
479         Buffers[2].buf = "\r\n";\r
480         Buffers[2].len = 2;\r
481         int z = 0;\r
483         // start sending the chunks\r
484         do\r
485         {\r
486                 z++;\r
487                 Buffers[1].buf = NULL;\r
488                 Buffers[1].len = 0;\r
489                 if (m_pNavData->pfnChunkCallback((BYTE**)&Buffers[1].buf, &Buffers[1].len, \r
490                         m_pNavData->m_lParamChunkCB))\r
491                 {\r
492                         _ATLTRY\r
493                         {\r
494                                 if (Buffers[1].len > 0)\r
495                                 {\r
496                                         // send the chunk\r
497                                         strChunkSize.Format("%x\r\n", Buffers[1].len);\r
498                                         Buffers[0].buf = (char*)(LPCSTR)strChunkSize;\r
499                                         Buffers[0].len = strChunkSize.GetLength();\r
500                                         if (!Write(Buffers, 3, &dwSent))\r
501                                         {\r
502                                                 bRet = false;\r
503                                                 break;\r
504                                         }\r
505                                 }\r
506                                 else if (Buffers[1].len == 0)\r
507                                 {\r
508                                         strChunkSize = "0\r\n\r\n\r\n";\r
509                                         Buffers[0].buf = (char*)(LPCSTR)strChunkSize;\r
510                                         Buffers[0].len = strChunkSize.GetLength();\r
511                                         if (!Write(Buffers, 1, &dwSent))\r
512                                         {\r
513                                                 bRet = false;\r
514                                                 break;\r
515                                         }\r
516                                         break;\r
517                                 }\r
518                         }\r
519                         _ATLCATCHALL()\r
520                         {\r
521                                 bRet = false;\r
522                                 break;\r
523                         }\r
524                 }\r
525                 else\r
526                 {\r
527                         bRet = false;\r
528                         break; // something went wrong in callback\r
529                 }\r
530         }while (Buffers[1].len > 0);\r
532         strRequest.ReleaseBuffer();\r
534         if (bRet)\r
535         {\r
536                 // Read the response\r
537                 if (RR_OK == ReadHttpResponse())\r
538                 {\r
539                         // if navigation isn't complete, try to complete\r
540                         // it based on the status code and flags\r
541                         if ((m_pNavData->dwFlags & ATL_HTTP_FLAG_PROCESS_RESULT)\r
542                                 && !ProcessStatus(m_pNavData->dwFlags))\r
543                         {\r
544                                 bRet = false;\r
545                         }\r
546                         bRet = true;\r
547                 }\r
548                 else\r
549                         bRet = false;\r
550         }\r
552         if (!bRet)\r
553                 Close();\r
555         return bRet;\r
558 template <class TSocketClass>\r
559 inline bool CAtlHttpClientT<TSocketClass>::ConnectSocket() throw()\r
561         bool bRet=false;\r
562         // connect to the correct server\r
563         if (GetProxy())\r
564         {\r
565                 //if we're using a proxy connect to the proxy\r
566                 bRet=Connect(m_strProxy, m_nProxyPort);\r
567         }\r
568         else\r
569         {\r
570                 bRet=Connect(m_urlCurrent.GetHostName(),m_urlCurrent.GetPortNumber()); // connect to the server\r
571         }               \r
572         return bRet;\r
576 template <class TSocketClass>\r
577 inline bool CAtlHttpClientT<TSocketClass>::BuildRequest(/*out*/CString *pstrRequest,\r
578                                                                                 LPCTSTR szMethod,\r
579                                                                                 LPCTSTR szExtraHeaders)  throw()\r
581         if (!m_pNavData)\r
582                 return false;\r
583         _ATLTRY\r
584         {\r
585                 // build up the request\r
586                 CString strRequest = szMethod;\r
587                 strRequest += _T(" ");\r
588                 if (GetProxy())\r
589                 {\r
590                         TCHAR buffURL[ATL_URL_MAX_URL_LENGTH];\r
591                         DWORD dwSize = ATL_URL_MAX_URL_LENGTH;\r
592                         m_urlCurrent.CreateUrl(buffURL, &dwSize);\r
593                         strRequest += buffURL;\r
595                         strRequest += ATL_HTTP_HEADER_PROXY;\r
596                         CString strHost;\r
597                         if (m_urlCurrent.GetPortNumber() != ATL_URL_DEFAULT_HTTP_PORT)\r
598                                 strHost.Format(_T("Host: %s:%d\r\n"), m_urlCurrent.GetHostName(), m_urlCurrent.GetPortNumber());\r
599                         else\r
600                                 strHost.Format(_T("Host: %s\r\n"), m_urlCurrent.GetHostName());\r
601                         strRequest += strHost;\r
603                         if (m_pNavData->dwDataLen>0)\r
604                         {\r
605                                 CString strCL;\r
606                                 strCL.Format(_T("Content-Length: %d\r\n"), m_pNavData->dwDataLen);\r
607                                 strRequest += strCL;\r
608                         }\r
610                         if (m_pNavData->szDataType)\r
611                         {\r
612                                 strRequest += _T("Content-Type: ");\r
613                                 strRequest += m_pNavData->szDataType;\r
614                                 strRequest += _T("\r\n");\r
615                         }\r
617                         if (m_pNavData->szExtraHeaders)\r
618                                 strRequest += szExtraHeaders;\r
619                         strRequest += ATL_HTTP_USERAGENT;\r
620                 }\r
621                 else\r
622                 {\r
623                         strRequest += m_urlCurrent.GetUrlPath();\r
624                         strRequest += m_urlCurrent.GetExtraInfo();\r
625                         strRequest += ATL_HTTP_HEADER;\r
627                         if (m_pNavData->dwDataLen > 0)\r
628                         {\r
629                                 CString strCL;\r
630                                 strCL.Format(_T("Content-Length: %d\r\n"), m_pNavData->dwDataLen);\r
631                                 strRequest += strCL;\r
632                         }\r
634                         if (m_pNavData->szDataType && \r
635                                 *m_pNavData->szDataType)\r
636                         {\r
637                                 strRequest += _T("Content-Type: ");\r
638                                 strRequest += m_pNavData->szDataType;\r
639                                 strRequest += _T("\r\n");\r
640                         }\r
642                         if (szExtraHeaders)\r
643                                 strRequest += szExtraHeaders;\r
646                         CString strHost;\r
647                         strHost.Format(_T("Host: %s\r\n"), m_urlCurrent.GetHostName());\r
648                         strRequest += strHost;\r
649                         strRequest += ATL_HTTP_USERAGENT;\r
650                 }\r
651                 strRequest += _T("\r\n");\r
654                 *pstrRequest = strRequest;\r
655                 return true;\r
656         }\r
657         _ATLCATCHALL()\r
658         {\r
659                 return false;\r
660         }\r
663 template <class TSocketClass>\r
664 inline bool CAtlHttpClientT<TSocketClass>::ReadSocket() throw()\r
666         bool bRet = false;\r
667         unsigned char read_buff[ATL_READ_BUFF_SIZE];\r
668         int dwSize = ATL_READ_BUFF_SIZE;\r
670         // read some data\r
671         for (int i = 0; i < ATL_HTTP_CLIENT_EMPTY_READ_RETRIES; ++i)\r
672         {\r
673                 bRet = Read(read_buff, (DWORD*)&dwSize);\r
674                 if (!bRet)\r
675                         return bRet;\r
677                 // notify user\r
678                 if (m_pNavData)\r
679                 {\r
680                         if (m_pNavData->pfnReadStatusCallback)\r
681                                 bRet = m_pNavData->pfnReadStatusCallback(dwSize, m_pNavData->m_lParamRead);\r
682                         if (!bRet)\r
683                                 return bRet;\r
684                 }\r
686                 if (dwSize > 0)\r
687                 {\r
688                         // append the data to our internal buffer\r
689                         // m_current holds bytes (not UNICODE!)\r
690                         \r
691                         if (!m_current.Append((LPCSTR)read_buff, dwSize))\r
692                                 return FALSE;\r
694                         m_pEnd = ((BYTE*)(LPCSTR)m_current) + m_current.GetLength();\r
695                         m_pCurrent = (BYTE*)(LPCSTR)m_current;\r
696                         break;\r
697                 }\r
698                 bRet = false; // nothing was read\r
699         }\r
701         return bRet;\r
704 // Starts searching for a complete header set at\r
705 // m_pCurrent. This function will only move m_pCurrent\r
706 // if a complete set is found. Returns the header beginning\r
707 // optionally.\r
708 template <class TSocketClass>\r
709 inline unsigned char* CAtlHttpClientT<TSocketClass>::FindHeaderEnd(unsigned char** ppBegin) throw()\r
711         if (!m_pCurrent)\r
712                 return NULL;\r
714         BYTE *pCurr = m_pCurrent;\r
715         BYTE *pBegin = m_pCurrent;\r
716         int nLen = m_current.GetLength();\r
718         if (pCurr >= (BYTE*)(LPCSTR)m_current + m_current.GetLength())\r
719                 return NULL; // no more chars in buffer\r
720         // look for the end of the header (the \r\n\r\n)\r
721         while (pCurr <= (pBegin + nLen - ATL_HEADER_END_LEN))\r
722         {\r
724                 if (* ((UNALIGNED  DWORD*)pCurr)==ATL_DW_HEADER_END)\r
725                 {\r
726                         // set m_pCurrent pointer to the end of the header\r
727                         m_pCurrent = pCurr + ATL_HEADER_END_LEN;\r
728                         if (ppBegin)\r
729                                 *ppBegin = pBegin;\r
730                         return m_pCurrent;\r
731                 }\r
732                 pCurr++;\r
733         }\r
734         return NULL;\r
737 // Call this function after sending an HTTP request over the socket. The complete\r
738 // HTTP response will be read. This function will also parse\r
739 // response headers into the response header map.\r
740 template <class TSocketClass>\r
741 inline typename CAtlHttpClientT<TSocketClass>::HTTP_RESPONSE_READ_STATUS CAtlHttpClientT<TSocketClass>::ReadHttpResponse() \r
743         // Read until we at least have the response headers\r
744         HTTP_RESPONSE_READ_STATUS result = RR_OK;\r
745         readstate state = rs_init;\r
746         unsigned char *pBodyBegin = NULL;\r
747         unsigned char *pHeaderBegin = NULL;\r
748         m_current.Empty();\r
749         m_pCurrent = NULL;\r
750         m_LastResponseParseError = RR_OK;\r
752         while (state != rs_complete)\r
753         {\r
754                 switch(state)\r
755                 {\r
756                 case rs_init:\r
757                         m_HeaderMap.RemoveAll();\r
758                         m_nStatus = ATL_INVALID_STATUS;\r
759                         m_dwHeaderLen = 0;\r
760                         m_dwBodyLen = 0;\r
761                         state = rs_readheader;\r
762                         // fall through\r
764                 case rs_readheader:\r
766                         // read from the socket until we have a complete set of headers.\r
767                         pBodyBegin = FindHeaderEnd(&pHeaderBegin);\r
768                         if (!pBodyBegin)\r
769                         {\r
770                                 if (!ReadSocket())\r
771                                 {\r
772                                         // Either reading from the socket failed, or there\r
773                                         // was not data to read. Set the nav status to error\r
774                                         // and change the state to complete.\r
775                                         state = rs_complete;\r
776                                         result = RR_READSOCKET_FAILED;\r
777                                         break;\r
778                                 }\r
779                                 else\r
780                                         break; // loop back and FindHeaderEnd again.\r
781                         }\r
782                         // we have a complete set of headers\r
783                         m_dwHeaderLen = (DWORD)(pBodyBegin-pHeaderBegin);\r
784                         m_dwHeaderStart = (DWORD)(pHeaderBegin - (BYTE*)(LPCSTR)m_current);\r
785                         // fall through\r
786                         state = rs_scanheader;\r
788                 case rs_scanheader:\r
789                         // set m_nStatus and check for valid status\r
790                         ParseStatusLine(pHeaderBegin);\r
791                         // failed to set m_nStatus;\r
792                         if (m_nStatus == ATL_INVALID_STATUS)\r
793                         {\r
794                                 state = rs_complete;\r
795                                 result = RR_STATUS_INVALID;\r
796                                 break;\r
797                         }\r
799                         else if (m_nStatus == 100) // continue\r
800                         {\r
801                                 state = rs_init;\r
802                                 break;\r
803                         }\r
805                         // crack all the headers and put them into a header map. We've already\r
806                         // done the check to make sure we have a complete set of headers in \r
807                         // rs_readheader above\r
808                         if (ATL_HEADER_PARSE_COMPLETE != CrackResponseHeader((LPCSTR)pHeaderBegin, \r
809                                 (LPCSTR*)&pBodyBegin))\r
810                         {\r
811                                 // something bad happened while parsing the headers!\r
812                                 state = rs_complete;\r
813                                 result = RR_PARSEHEADERS_FAILED;\r
814                                 break;\r
815                         }\r
816                         state = rs_readbody;\r
817                         // fall through\r
819                 case rs_readbody:\r
820                         // headers are parsed and cracked, we're ready to read the rest\r
821                         // of the response. \r
822                         if (IsMsgBodyChunked())\r
823                         {\r
824                                 if (!ReadChunkedBody())\r
825                                 {\r
826                                         result = RR_READCHUNKEDBODY_FAILED;\r
827                                         state = rs_complete;\r
828                                         break;\r
829                                 }\r
830                         }\r
831                         else\r
832                         if (!ReadBody(GetContentLength(), m_current.GetLength()-(m_dwHeaderStart+m_dwHeaderLen)))\r
833                                 result = RR_READBODY_FAILED;\r
834                         state = rs_complete;\r
835                         //fall through\r
837                 case rs_complete:\r
838                         // clean up the connection if the server requested a close;\r
839                         DisconnectIfRequired();\r
840                         break;\r
841                 }\r
842         }\r
843         m_LastResponseParseError = result;\r
844         return result;\r
847 template <class TSocketClass>\r
848 inline typename CAtlHttpClientT<TSocketClass>::HTTP_RESPONSE_READ_STATUS CAtlHttpClientT<TSocketClass>::GetResponseStatus()\r
850         return m_LastResponseParseError;\r
853 // Checks to see if the server has closed the connection.\r
854 // If it has, we create a new socket and reconnect it to\r
855 // the current server. This also clears the contents of the\r
856 // current response buffer.\r
857 template <class TSocketClass>\r
858 inline void CAtlHttpClientT<TSocketClass>::ResetConnection() throw()\r
860         ReconnectIfRequired();\r
861         m_HeaderMap.RemoveAll();\r
862         m_current.Empty();\r
863         m_nStatus = ATL_INVALID_STATUS;\r
864         m_AuthTypes.RemoveAll(); // the server will keep sending back www-authenticate\r
865                                                          // headers until the connection is authorized\r
868 // Takes action based on the flags passed and the current\r
869 // status for this object.\r
870 template <class TSocketClass>\r
871 inline bool CAtlHttpClientT<TSocketClass>::ProcessStatus(DWORD dwFlags) throw()\r
873         switch(m_nStatus)\r
874         {\r
875         case 200: // In all these cases there is no further action\r
876         case 201: // to take. Any additional informaion is returned\r
877         case 202: // in the entity body.\r
878         case 203:\r
879         case 204:\r
880         case 205:\r
881         case 206:\r
882         case 304:\r
883         case 305:\r
884                 return true;\r
885                 break;\r
886         case 301:\r
887         case 302:\r
888         case 303:\r
889                 if (dwFlags & ATL_HTTP_FLAG_AUTO_REDIRECT)\r
890                         return ProcessObjectMoved();\r
891                 break;\r
892         case 401: // auth required\r
893                         return NegotiateAuth(false);\r
894                 break;\r
895         case 407: // proxy auth required\r
896                         return NegotiateAuth(true);\r
897                 break;\r
899         }\r
900         return false;\r
903 // Looks up the value of a response header in the header map. Call with\r
904 // NULL szBuffer to have length of the required buffer placed in \r
905 // pdwLen on output.\r
907 // szName is the name of the header to look up.\r
908 // szBuffer is the buffer that will contain the looked up string.\r
909 // pdwLen contains the length of szBuffer in characters on input and the length\r
910 // of the string including NULL terminator in characters on output.\r
911 template<class TSocketClass>\r
912 inline bool CAtlHttpClientT<TSocketClass>::GetHeaderValue(LPCTSTR szName, CString& strValue) const throw()\r
914         _ATLTRY\r
915         {\r
916                 return m_HeaderMap.Lookup(szName, strValue);\r
917         }\r
918         _ATLCATCHALL()\r
919         {\r
920                 return false;\r
921         }\r
924 template<class TSocketClass>\r
925 inline bool CAtlHttpClientT<TSocketClass>::GetHeaderValue(__in_z LPCTSTR szName, __out_ecount_part_z_opt(*pdwLen, *pdwLen) LPTSTR szBuffer, __inout DWORD *pdwLen) const throw()\r
927         CString strValue;\r
928         bool bRet = GetHeaderValue(szName, strValue);\r
929         DWORD nLen = strValue.GetLength();\r
930         if (!bRet)\r
931                 return false;\r
933         if ((pdwLen && *pdwLen < nLen+1) ||\r
934                 (!szBuffer && pdwLen) )\r
935         {\r
936                 *pdwLen = nLen+1;\r
937                 return true;\r
938         }\r
940         if (!szBuffer)\r
941                 return false;\r
943         Checked::tcsncpy_s(szBuffer, nLen+1, (LPCTSTR)strValue, _TRUNCATE);\r
944         if (pdwLen)\r
945                 *pdwLen = nLen+1;\r
946         return true;\r
949 // Adds an authorization object to use for a particular scheme.\r
950 // This will overwrite an existing entry if an object for the \r
951 // same scheme has already been set.\r
952 template<class TSocketClass>\r
953 inline bool CAtlHttpClientT<TSocketClass>::AddAuthObj(LPCTSTR szScheme,\r
954                                 CAtlBaseAuthObject *pObject, IAuthInfo *pInfo/*=NULL*/) throw()\r
956         if (!pObject)\r
957                 return false;\r
959         pObject->Init(this, pInfo);\r
961         _ATLTRY\r
962         {\r
963                 POSITION pos = m_AuthMap.SetAt(szScheme, pObject);\r
964                 if (!pos)\r
965                         return false;\r
966         }\r
967         _ATLCATCHALL()\r
968         {\r
969                 return false;\r
970         }\r
972         return true;\r
975 // Tries to find an authorization object to use for a particular\r
976 // scheme\r
977 template<class TSocketClass>\r
978 inline const CAtlBaseAuthObject* CAtlHttpClientT<TSocketClass>::FindAuthObject(LPCTSTR szScheme) throw()\r
980         CAtlBaseAuthObject *pObject = NULL;\r
981         if (m_AuthMap.Lookup(szScheme, pObject))\r
982         {\r
983                 return const_cast<const CAtlBaseAuthObject*>(pObject);\r
984         }\r
985         return NULL;\r
988 // Removes an existing authorization object from the map.\r
989 template<class TSocketClass>\r
990 inline bool CAtlHttpClientT<TSocketClass>::RemoveAuthObject(LPCTSTR szScheme) throw()\r
992         return m_AuthMap.RemoveKey(szScheme);\r
995 // Sets the current proxy server and port\r
996 template<class TSocketClass>\r
997 inline bool CAtlHttpClientT<TSocketClass>::SetProxy(LPCTSTR szProxy, short nProxyPort) throw()\r
999         if (!szProxy)\r
1000         {\r
1001                 if (!LookupRegProxy())\r
1002                         return false;\r
1003         }\r
1004         else\r
1005         {\r
1006                 _ATLTRY\r
1007                 {\r
1008                         m_strProxy = szProxy;\r
1009                         m_nProxyPort = nProxyPort;\r
1010                 }\r
1011                 _ATLCATCHALL()\r
1012                 {\r
1013                         return false;\r
1014                 }\r
1015         }\r
1016         return true;\r
1019 // Removes the current proxy settings.\r
1020 template<class TSocketClass>\r
1021 inline void CAtlHttpClientT<TSocketClass>::RemoveProxy() throw()\r
1023                 m_strProxy.Empty();\r
1024                 m_nProxyPort = ATL_URL_INVALID_PORT_NUMBER;\r
1027 // retrieves the current proxy\r
1028 template<class TSocketClass>\r
1029 inline LPCTSTR CAtlHttpClientT<TSocketClass>::GetProxy() const throw()\r
1031         if (m_strProxy.GetLength())\r
1032                 return (LPCTSTR)m_strProxy;\r
1033         return NULL;\r
1036 template<class TSocketClass>\r
1037 inline short CAtlHttpClientT<TSocketClass>::GetProxyPort() const throw()\r
1039         return m_nProxyPort;\r
1042 // Gets the contents of the entire response buffer.\r
1043 template<class TSocketClass>\r
1044 inline const BYTE* CAtlHttpClientT<TSocketClass>::GetResponse() throw()\r
1046         return (const BYTE*)(LPCSTR)m_current;\r
1049 template<class TSocketClass>\r
1050 inline DWORD CAtlHttpClientT<TSocketClass>::GetResponseLength() throw()\r
1052         return m_current.GetLength();\r
1055 // Gets the length in bytes of the body of the\r
1056 // current response\r
1057 template<class TSocketClass>\r
1058 inline DWORD CAtlHttpClientT<TSocketClass>::GetBodyLength() const throw()\r
1060         return m_dwBodyLen;\r
1063 // Gets the contents of the body of the current response. This\r
1064 // is the response without the headers. \r
1065 template<class TSocketClass>\r
1066 inline const BYTE* CAtlHttpClientT<TSocketClass>::GetBody() throw()\r
1068         return (BYTE*)((LPCSTR)m_current + m_dwHeaderLen + m_dwHeaderStart);\r
1071 // Get the length of the header part of the response in bytes.\r
1072 template<class TSocketClass>\r
1073 inline DWORD CAtlHttpClientT<TSocketClass>::GetRawResponseHeaderLength() throw()\r
1075         return m_dwHeaderLen >= 2 ? m_dwHeaderLen-2 : 0; // m_dwHeaderLen includes the final \r\n\r
1078 // buffer must include space for null terminator.\r
1079 // on input, pdwLen specifies the size of szBuffer,\r
1080 // on output, pdwLen holds the number of bytes copied\r
1081 // to szBuffer, or the required size of szBuffer if \r
1082 // szBuffer wasn't big enough\r
1083 template<class TSocketClass>\r
1084 inline bool CAtlHttpClientT<TSocketClass>::GetRawResponseHeader(LPBYTE szBuffer, DWORD *pdwLen) throw()\r
1086         if (!pdwLen)\r
1087                 return false;\r
1089         DWORD header_len = GetRawResponseHeaderLength();\r
1090         if (header_len == 0)\r
1091                 return false;\r
1093         if (!szBuffer || *pdwLen < header_len+1)\r
1094         {\r
1095                 *pdwLen = header_len+1;\r
1096                 return false;\r
1097         }\r
1099         Checked::memcpy_s(szBuffer, *pdwLen, (BYTE*)(LPCSTR)m_current, header_len);\r
1100         szBuffer[header_len]='\0';\r
1102         *pdwLen = header_len+1;\r
1103         return true;\r
1106 // Gets the current URL object.\r
1107 template<class TSocketClass>\r
1108 inline LPCURL CAtlHttpClientT<TSocketClass>::GetCurrentUrl() const throw()\r
1110         return (LPCURL)&m_urlCurrent;\r
1113 template<class TSocketClass>\r
1114 inline bool CAtlHttpClientT<TSocketClass>::SetDefaultUrl(  LPCTSTR szUrl, \r
1115                                                                                         short nPortNumber) throw()\r
1117         return _SetDefaultUrl(szUrl,nPortNumber);\r
1120 template<class TSocketClass>\r
1121 inline bool CAtlHttpClientT<TSocketClass>::SetDefaultUrl(  LPCURL pUrl, \r
1122                                                                                         short nPortNumber) throw()\r
1124         m_urlCurrent = *pUrl;\r
1125         return _SetDefaultUrl(NULL, nPortNumber);\r
1128 template<class TSocketClass>\r
1129 inline bool CAtlHttpClientT<TSocketClass>::SetDefaultMethod(LPCTSTR szMethod) throw()\r
1132         _ATLTRY\r
1133         {\r
1134                 m_strMethod = szMethod;\r
1135                 return true;\r
1136         }\r
1137         _ATLCATCHALL()\r
1138         {\r
1139                 return false;\r
1140         }\r
1143 template<class TSocketClass>\r
1144 inline DWORD CAtlHttpClientT<TSocketClass>::GetFlags() const throw()\r
1146         if (m_pNavData)\r
1147                 return m_pNavData->dwFlags;\r
1148         else\r
1149                 return ATL_HTTP_FLAG_INVALID_FLAGS;\r
1152 template<class TSocketClass>\r
1153 inline bool CAtlHttpClientT<TSocketClass>::LookupRegProxy() throw()\r
1155         // attempt to look it up from the registry\r
1156         CRegKey rkProxy;\r
1157         ULONG nChars = ATL_URL_MAX_URL_LENGTH+1;\r
1158         TCHAR szUrl[ATL_URL_MAX_URL_LENGTH+1] = { 0 };\r
1160         DWORD dwErr = rkProxy.Open(HKEY_CURRENT_USER, \r
1161                 _T("Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings"), KEY_READ);\r
1162         if (dwErr == ERROR_SUCCESS)\r
1163         {\r
1164                 dwErr = rkProxy.QueryStringValue(_T("ProxyServer"), szUrl, &nChars);\r
1165         }\r
1166         if (dwErr == ERROR_SUCCESS)\r
1167         {\r
1168                 CUrl url;\r
1169                 if (url.CrackUrl(szUrl))\r
1170                 {\r
1171                         if (url.GetScheme()==ATL_URL_SCHEME_UNKNOWN)\r
1172                         {\r
1173                                 // without the scheme name (e.g. proxy:80)\r
1174                                 m_strProxy = url.GetSchemeName();\r
1175                                 m_nProxyPort = (short)_ttoi(url.GetHostName());\r
1176                                 return true;\r
1177                         }\r
1178                         else if (url.GetHostName())\r
1179                         {\r
1180                                 // with the scheme (e.g. http://proxy:80)\r
1181                                 m_strProxy = url.GetHostName();\r
1182                                 m_nProxyPort = url.GetPortNumber();\r
1183                                 return true;\r
1184                         }\r
1185                 }\r
1186         }\r
1187         return false;\r
1190 template<class TSocketClass>\r
1191 inline bool CAtlHttpClientT<TSocketClass>::DisconnectIfRequired() throw()\r
1193         CString strValue;\r
1194         if (GetHeaderValue(_T("Connection"), strValue) && !strValue.CompareNoCase(_T("close")))\r
1195         {\r
1196                 Close();\r
1197         }\r
1199         return true;\r
1202 class CInitializeCOMThread\r
1204 public:\r
1205         CInitializeCOMThread()\r
1206                 : m_bCoInit(FALSE),m_bShouldUninit(FALSE)\r
1207         {               \r
1208                 //At this point the Thread can be uninit, init to STA or init to MTA.\r
1209                 //CoInitialize can always fail unexpectedly.            \r
1210                 HRESULT hr = ::CoInitialize(NULL);              \r
1211                 if (SUCCEEDED(hr))\r
1212                 {\r
1213                         m_bCoInit=TRUE;\r
1214                         m_bShouldUninit=TRUE;\r
1215                 } else if (hr == RPC_E_CHANGED_MODE)\r
1216                 {       \r
1217                         m_bCoInit=TRUE;\r
1218                 }\r
1219         }\r
1220         ~CInitializeCOMThread()\r
1221         {\r
1222                 if (m_bShouldUninit)\r
1223                 {\r
1224                         ::CoUninitialize();\r
1225                 }\r
1226         }\r
1227         BOOL IsInitialized() {  return m_bCoInit; }\r
1228 protected:\r
1229         BOOL m_bCoInit;\r
1230         BOOL m_bShouldUninit;\r
1231 };\r
1232 // Tries to find an authorization object that meets\r
1233 template<class TSocketClass>\r
1234 inline bool CAtlHttpClientT<TSocketClass>::NegotiateAuth(bool bProxy) throw()\r
1236         //Test if can silently pass user credentials to server.\r
1237         if (!m_bSilentLogonOk)\r
1238         {       \r
1239                 //Call CoInit, because ATL Http code cannot assume it has already been called by the user.\r
1240                 CInitializeCOMThread initThread;\r
1241                 if (initThread.IsInitialized())\r
1242                 {\r
1243                         HRESULT hr = S_OK;\r
1244                         CComPtr<IInternetSecurityManager> spSecurityMgr;\r
1245                         \r
1246                         hr = CoCreateInstance(CLSID_InternetSecurityManager, NULL, CLSCTX_INPROC_SERVER,\r
1247                                                                         IID_IInternetSecurityManager, (void**)&spSecurityMgr);\r
1248                         if (SUCCEEDED(hr))\r
1249                         {               \r
1250                                 TCHAR szUrl[ATL_URL_MAX_URL_LENGTH];\r
1251                                 DWORD dwMaxLen = ATL_URL_MAX_URL_LENGTH;\r
1252                                 if (!m_urlCurrent.CreateUrl(szUrl, &dwMaxLen))\r
1253                                 {\r
1254                                         return false;\r
1255                                 }\r
1256                                 \r
1257                                 CStringW strUrlW(szUrl);\r
1258                                 DWORD dwPolicy=0xFFFF;          \r
1259                                 hr=spSecurityMgr->ProcessUrlAction(strUrlW.GetString(),\r
1260                                                                                                 URLACTION_CREDENTIALS_USE,\r
1261                                                                                                 reinterpret_cast<BYTE*>(&dwPolicy),\r
1262                                                                                                 sizeof(dwPolicy),\r
1263                                                                                                 NULL,\r
1264                                                                                                 0,\r
1265                                                                                                 PUAF_NOUI,\r
1266                                                                                                 NULL);\r
1268                                 if (FAILED(hr) || dwPolicy != URLPOLICY_CREDENTIALS_SILENT_LOGON_OK)\r
1269                                 {\r
1270                                         return false;\r
1271                                 }\r
1272                         }\r
1273                         else\r
1274                         {\r
1275                                 // CoCreateInstance failed, return false\r
1276                                 return false;\r
1277                         }\r
1278                 }\r
1279                 else\r
1280                 {\r
1281                         // CoInit failed, return false\r
1282                         return false;\r
1283                 }\r
1284         }\r
1286         // szAuthHeaderValue should contain a comma separated list\r
1287         // of authentication types\r
1288         CAtlBaseAuthObject *pAuthObj = NULL;\r
1289         bool bRet = false;\r
1290         for (size_t i = 0; i<m_AuthTypes.GetCount(); i++)\r
1291         {\r
1292                 _ATLTRY\r
1293                 {\r
1294                         CString strName = m_AuthTypes[i];\r
1295                         int nSpace = strName.Find(_T(' '));\r
1296                         if (nSpace!=-1)\r
1297                                 strName.SetAt(nSpace,0);\r
1299                         if (m_AuthMap.Lookup(strName, pAuthObj) &&\r
1300                                 !pAuthObj->m_bFailed)\r
1301                                 bRet = pAuthObj->Authenticate(m_AuthTypes[i], bProxy);\r
1303                         if (bRet)\r
1304                                 return bRet;\r
1305                 }\r
1306                 _ATLCATCHALL()\r
1307                 {\r
1308                         bRet = false;\r
1309                 }\r
1310         }\r
1311         return bRet;\r
1314 template<class TSocketClass>\r
1315 inline long CAtlHttpClientT<TSocketClass>::GetContentLength() throw()\r
1317         CString strValue;\r
1318         if (GetHeaderValue(_T("Content-Length"), strValue))\r
1319         {\r
1320                 TCHAR *pStop = NULL;\r
1321                 return _tcstol(strValue, &pStop, 10);\r
1322         }\r
1323         else\r
1324                 return -1;\r
1327 template<class TSocketClass>\r
1328 inline LPCSTR CAtlHttpClientT<TSocketClass>::NextLine(BYTE* pCurr) throw()\r
1330         if (!pCurr)\r
1331                 return NULL;\r
1333         while ( pCurr < m_pEnd && *pCurr && !(*pCurr == '\r' && *(pCurr+1) == '\n'))\r
1334                 pCurr++;\r
1336         if (pCurr >= m_pEnd)\r
1337                 return NULL;\r
1339 //      if (pCurr < m_pEnd-4)\r
1340 //              if (!memcmp(pCurr, ATL_HEADER_END, 4))\r
1341                         //return NULL;\r
1343         return (LPCSTR)(pCurr+2);\r
1346 template<class TSocketClass>\r
1347 inline bool CAtlHttpClientT<TSocketClass>::IsMsgBodyChunked() throw()\r
1349         CString strValue;\r
1350         return (\r
1351                         GetHeaderValue(_T("Transfer-Encoding"), strValue) &&\r
1352                         !strValue.CompareNoCase(_T("chunked"))\r
1353                         );\r
1357 // finds the end of an individual header field pointed to by\r
1358 // pszStart. Header fields can be multi-line with multi-line \r
1359 // header fields being a line that starts with some kind of \r
1360 // white space.\r
1361 template<class TSocketClass>\r
1362 inline LPCSTR CAtlHttpClientT<TSocketClass>::FindEndOfHeader(LPCSTR pszStart) throw()\r
1364         // move through all the lines until we come to one\r
1365         // that doesn't start with white space\r
1366         LPCSTR pLineStart = pszStart;\r
1367         LPCSTR pHeaderEnd = NULL;\r
1369         do \r
1370         {\r
1371                 pLineStart = NextLine((BYTE*)pLineStart);\r
1372         }while (pLineStart && isspace(static_cast<unsigned char>(*pLineStart)) && strncmp(pLineStart-2, ATL_HEADER_END, ATL_HEADER_END_LEN));\r
1374         if (pLineStart > (LPCSTR)m_pEnd)\r
1375                 return NULL; // ran out of data in the buffer without finding the end of a line\r
1376                          // or the end of the headers.\r
1378         if (pLineStart)\r
1379                 pHeaderEnd = pLineStart-2;\r
1380         else\r
1381                 pHeaderEnd = NULL;\r
1383         return pHeaderEnd;\r
1386 template<class TSocketClass>\r
1387 inline bool CAtlHttpClientT<TSocketClass>::DecodeHeader(LPCSTR pHeaderStart, LPCSTR pHeaderEnd) throw()\r
1389         _ATLTRY\r
1390         {\r
1391                 if (!pHeaderStart || !pHeaderEnd)\r
1392                         return false;\r
1393                 LPCSTR pTemp = pHeaderStart;\r
1394                 while (*pTemp != ATL_FIELDNAME_DELIMITER && pTemp < pHeaderEnd)\r
1395                         pTemp++;\r
1396                 if (*pTemp == ATL_FIELDNAME_DELIMITER)\r
1397                 {\r
1398                         char szName[ATL_MAX_FIELDNAME_LEN];\r
1399                         char szValue[ATL_MAX_VALUE_LEN];\r
1400                         int nLen = (int)(pTemp-pHeaderStart) ;\r
1401                         ATLASSERT(nLen < ATL_MAX_FIELDNAME_LEN);\r
1402                         if (nLen >= ATL_MAX_FIELDNAME_LEN)\r
1403                                 return false; // won't fit in the buffer.\r
1404                         Checked::memcpy_s(szName, ATL_MAX_FIELDNAME_LEN, pHeaderStart, nLen);\r
1405                         szName[nLen]=0;\r
1407                         pTemp++; // move past delimiter;\r
1408                         while (isspace(static_cast<unsigned char>(*pTemp)) && pTemp < pHeaderEnd)\r
1409                                 pTemp++;\r
1411                         nLen = (int)(pHeaderEnd-pTemp);\r
1412                         ATLASSERT(nLen < ATL_MAX_VALUE_LEN);\r
1413                         if (nLen >= ATL_MAX_VALUE_LEN)\r
1414                                 return false; // won't fit in the buffer\r
1415                         Checked::memcpy_s(szValue, ATL_MAX_VALUE_LEN, pTemp, nLen);\r
1416                         szValue[nLen]=0;\r
1418                         CString strExist;\r
1419                         CA2T pszName(szName);\r
1420                         CA2T pszValue(szValue);\r
1422                         if (!_tcsicmp(pszName, _T("www-authenticate")) ||\r
1423                                 !_tcsicmp(pszName, _T("proxy-authenticate")))\r
1424                         {\r
1425                                 m_AuthTypes.Add(pszValue);\r
1426                         }\r
1428                         if (!m_HeaderMap.Lookup(pszName, strExist))\r
1429                                 m_HeaderMap.SetAt(pszName, pszValue);\r
1430                         else\r
1431                         {   \r
1432                                 // field-values for headers with the same name can be appended\r
1433                                 // per rfc2068 4.2, we do the appending so we don't have to\r
1434                                 // store/lookup duplicate keys.\r
1435                                 strExist += ',';\r
1436                                 strExist += pszValue;\r
1437                                 m_HeaderMap.SetAt(pszName, (LPCTSTR)strExist);\r
1438                         }\r
1440                         // if it's a set-cookie header notify users so they can do \r
1441                         // somthing with it.\r
1442                         if (!_tcsicmp(pszName, _T("set-cookie")))\r
1443                                 OnSetCookie(pszValue);\r
1444                 }\r
1446                 return true;\r
1447         }\r
1448         _ATLCATCHALL()\r
1449         {\r
1450                 return false;\r
1451         }\r
1454 template<class TSocketClass>\r
1455 inline void CAtlHttpClientT<TSocketClass>::OnSetCookie(LPCTSTR) throw()\r
1457         return;\r
1460 template<class TSocketClass>\r
1461 inline LPCSTR CAtlHttpClientT<TSocketClass>::ParseStatusLine(BYTE* pBuffer) throw()\r
1463         if (!pBuffer)\r
1464                 return NULL;\r
1465         if (m_pEnd <= pBuffer)\r
1466                 return NULL;\r
1468         // find the first space'\r
1469         while (pBuffer < m_pEnd && !isspace(static_cast<unsigned char>(*pBuffer)))\r
1470                 pBuffer++;\r
1472         if (pBuffer >= m_pEnd)\r
1473                 return NULL;\r
1475         // move past the space\r
1476         while (pBuffer < m_pEnd && isspace(static_cast<unsigned char>(*pBuffer)))\r
1477                 pBuffer++;\r
1479         if (pBuffer >= m_pEnd)\r
1480                 return NULL;\r
1482         // pBuffer better be pointing at the status code now\r
1483         LPCSTR pEnd = NULL;\r
1484         if (*pBuffer >= '0' && *pBuffer <= '9')\r
1485         {\r
1486                 // probably a good status code\r
1487                 errno_t errnoValue = AtlStrToNum(&m_nStatus, (LPSTR)pBuffer, (LPSTR*)&pEnd, 10);\r
1488                 if (errnoValue == ERANGE)\r
1489                         return NULL; // bad status code\r
1490         }\r
1491         else \r
1492                 return FALSE; // bad status code;\r
1494         if (!pEnd)\r
1495                 return FALSE; // bad status code;\r
1497         pBuffer = (BYTE*)pEnd;\r
1498         // move to end of line\r
1499         while (pBuffer < m_pEnd && *pBuffer !=  '\n')\r
1500                 pBuffer++;\r
1502         if (pBuffer >= m_pEnd)\r
1503                 return NULL;\r
1505         // set the return pointing to the first \r
1506         // character after our status line.\r
1507         return (LPCSTR)++pBuffer;\r
1511 // pBuffer should start at the first character\r
1512 // after the status line.\r
1513 template<class TSocketClass>\r
1514 inline int CAtlHttpClientT<TSocketClass>::CrackResponseHeader(LPCSTR pBuffer, /*out*/ LPCSTR *pEnd) throw()\r
1516         // read up to the double /r/n\r
1517         LPCSTR pszStartSearch = pBuffer;\r
1518         if (!pEnd)\r
1519                 return ATL_HEADER_PARSE_HEADERERROR;\r
1521         *pEnd = NULL;\r
1522         if (pszStartSearch == NULL)\r
1523                 return ATL_HEADER_PARSE_HEADERERROR;\r
1525         // start parsing headers\r
1526         LPCSTR pHeaderStart = ParseStatusLine((BYTE*)pBuffer);\r
1527         if (!pHeaderStart)\r
1528                 return ATL_HEADER_PARSE_HEADERERROR;\r
1529         LPCSTR pHeaderEnd = NULL;\r
1531         while (pHeaderStart && *pHeaderStart && pHeaderStart < (LPCSTR)m_pEnd)\r
1532         {\r
1533                 pHeaderEnd = FindEndOfHeader(pHeaderStart);\r
1534                 if (!pHeaderEnd)\r
1535                         break; // error\r
1537                 DecodeHeader(pHeaderStart, pHeaderEnd);\r
1539                 if (!strncmp(pHeaderEnd, ATL_HEADER_END, strlen(ATL_HEADER_END)))\r
1540                 {\r
1541                         *pEnd = pHeaderEnd + strlen(ATL_HEADER_END);\r
1542                         break;      // we're done\r
1543                 }\r
1544                 else\r
1545                         pHeaderStart = pHeaderEnd+2;\r
1546         }\r
1548         return ATL_HEADER_PARSE_COMPLETE;\r
1551 // Reads the body if the encoding is not chunked.\r
1552 template<class TSocketClass>\r
1553 inline bool CAtlHttpClientT<TSocketClass>::ReadBody(int nContentLen, int nCurrentBodyLen) throw()\r
1555         // nCurrentBodyLen is the length of the body that has already been read\r
1556         // nContentLen is the value of Content-Length\r
1557         // current is the buffer that will contain the entire response\r
1558         bool bRet = true;\r
1559         ATLASSUME(m_pNavData);\r
1560         if (!m_pNavData)\r
1561                 return false;\r
1563         CTempBuffer<BYTE, 512> readbuff;\r
1564         DWORD dwReadBuffSize = 0;\r
1565         DWORD dwRead = 0;\r
1566         if (m_pNavData->dwReadBlockSize)\r
1567         {\r
1568                 ATLTRY(readbuff.Allocate(m_pNavData->dwReadBlockSize));\r
1569                 dwReadBuffSize = m_pNavData->dwReadBlockSize;\r
1570         }\r
1571         else\r
1572         {\r
1573                 ATLTRY(readbuff.Allocate(ATL_READ_BUFF_SIZE));\r
1574                 dwReadBuffSize = ATL_READ_BUFF_SIZE;\r
1575         }\r
1577         if (readbuff.operator BYTE*() == NULL)\r
1578                 return false;\r
1580         if (nContentLen != -1) // We know the content length.\r
1581         {\r
1582                 // read the rest of the body.\r
1583                 while (nCurrentBodyLen < nContentLen)\r
1584                 {\r
1585                         dwRead = dwReadBuffSize;\r
1586                         // loop while dwRead == 0\r
1587                         for (int nRetry = 0; nRetry < ATL_HTTP_CLIENT_EMPTY_READ_RETRIES; ++nRetry)\r
1588                         {\r
1589                                 if (!Read(readbuff, &dwRead))\r
1590                                         return false;\r
1591         \r
1592                                 // notify user\r
1593                                 if (m_pNavData)\r
1594                                 {\r
1595                                         if (m_pNavData->pfnReadStatusCallback)\r
1596                                                 if (!m_pNavData->pfnReadStatusCallback(dwRead, m_pNavData->m_lParamRead))\r
1597                                                         return false;\r
1598                                 }\r
1599         \r
1600                                 if (dwRead == 0)\r
1601                                         continue;\r
1602                                 nCurrentBodyLen += dwRead;\r
1603                                 if (!m_current.Append((LPCSTR)(BYTE*)readbuff, dwRead))\r
1604                                 {\r
1605                                         ATLASSERT(0);\r
1606                                         return false; // error!\r
1607                                 }\r
1608                                 m_pEnd = ((BYTE*)(LPCSTR)m_current) + m_current.GetLength();\r
1609                                 break;\r
1610                         }\r
1611                         if (dwRead == 0)\r
1612                                 return false;\r
1613                 }\r
1614                 m_dwBodyLen = nCurrentBodyLen;\r
1615         }\r
1616         else // We don't know content length. All we can do is\r
1617         {    // read until there is nothing else to read.\r
1618                 int nRetries = 0;\r
1619                 while (1)\r
1620                 {\r
1621                         dwRead = dwReadBuffSize;\r
1622                         if (Read((BYTE*)readbuff, (DWORD*)&dwRead))\r
1623                         {\r
1624                                 // notify user\r
1625                                 if (m_pNavData)\r
1626                                 {\r
1627                                         if (m_pNavData->pfnReadStatusCallback)\r
1628                                                 bRet = m_pNavData->pfnReadStatusCallback(dwRead, m_pNavData->m_lParamRead);\r
1629                                         if (!bRet)\r
1630                                                 return bRet;\r
1631                                 }\r
1633                                 if (dwRead == 0)\r
1634                                 {\r
1635                                         if (nRetries++ < ATL_HTTP_CLIENT_EMPTY_READ_RETRIES)\r
1636                                                 continue;\r
1637                                         break;\r
1638                                 }\r
1640                                 nRetries = 0;\r
1641                                 nCurrentBodyLen += dwRead;\r
1642                                 if (!m_current.Append((LPCSTR)(BYTE*)readbuff, dwRead))\r
1643                                         return false;\r
1644                                 m_pEnd = ((BYTE*)(LPCSTR)m_current) + m_current.GetLength();\r
1645                         }\r
1646                         else \r
1647                         {\r
1648                                 // notify user\r
1649                                 if (m_pNavData)\r
1650                                 {\r
1651                                         if (m_pNavData->pfnReadStatusCallback)\r
1652                                                 bRet = m_pNavData->pfnReadStatusCallback(dwRead, m_pNavData->m_lParamRead);\r
1653                                         if (!bRet)\r
1654                                                 return bRet;\r
1655                                 }\r
1657                                 bRet = true;\r
1658                                 break;\r
1659                         }\r
1660                 }\r
1661                 m_dwBodyLen = nCurrentBodyLen;\r
1662         }\r
1663         return bRet;\r
1667 // This function moves pBuffStart only on success. On success, pBuffStart is moved\r
1668 // to the element past the last element we consumed.\r
1669 template<class TSocketClass>\r
1670 inline typename CAtlHttpClientT<TSocketClass>::CHUNK_LEX_RESULT CAtlHttpClientT<TSocketClass>::get_chunked_size(char *&pBuffStart, char *&pBuffEnd, long* pnChunkSize) throw()\r
1672         CHUNK_LEX_RESULT result = LEX_ERROR;\r
1673         char *pStop = NULL;\r
1675         if (pBuffStart >= pBuffEnd)\r
1676                 result = LEX_OUTOFDATA;\r
1677         else\r
1678         {\r
1679                 long nResult = 0;\r
1680                 errno_t errnoValue = AtlStrToNum(&nResult, pBuffStart, &pStop, 16);\r
1681                 if (errnoValue != ERANGE &&\r
1682                         nResult >= 0 &&\r
1683                         nResult < 0xFFFFFFFF &&\r
1684                         pStop <= pBuffEnd &&\r
1685                         *pStop == '\r')\r
1686                 {\r
1687                         // move pBuffStart\r
1688                         // return chunk size\r
1689                         *pnChunkSize = nResult;\r
1690                         pBuffStart = pStop;\r
1691                         result = LEX_OK;\r
1692                 }\r
1693                 if (*pStop != '\r')\r
1694                 {\r
1695                         result = LEX_OUTOFDATA; // not enough data in the buffer\r
1696                 }\r
1697         }\r
1698         return result;\r
1701 template<class TSocketClass>\r
1702 inline bool CAtlHttpClientT<TSocketClass>::move_leftover_bytes( __in_ecount(nLen) char *pBufferStart, \r
1703                                                                 __in int nLen, \r
1704                                                                 __deref_inout_ecount(nLen) char *&pBuffStart, \r
1705                                                                 __deref_inout char *& pBuffEnd) throw()\r
1707         bool bRet = true;\r
1708         Checked::memcpy_s(pBufferStart, (pBuffEnd-pBuffStart), pBuffStart, nLen);\r
1709         return bRet;\r
1712 template<class TSocketClass>\r
1713 inline typename CAtlHttpClientT<TSocketClass>::CHUNK_LEX_RESULT CAtlHttpClientT<TSocketClass>::get_chunked_data(char *&pBufferStart,\r
1714                                                                   char *&pBufferEnd,\r
1715                                                                   long nChunkSize,\r
1716                                                                   char **ppDataStart,\r
1717                                                                   long *pnDataLen) throw()\r
1719         CHUNK_LEX_RESULT result = LEX_ERROR;\r
1720         if (pBufferStart + nChunkSize - 1 < pBufferEnd)\r
1721         {\r
1722                 *ppDataStart = pBufferStart;\r
1723                 *pnDataLen = nChunkSize;\r
1724                 pBufferStart = pBufferStart + nChunkSize;\r
1725                 result = LEX_OK;\r
1726         }\r
1727         else if (pBufferStart + nChunkSize - 1 >= pBufferEnd)\r
1728                 result = LEX_OUTOFDATA;\r
1730         return result;\r
1733 template<class TSocketClass>\r
1734 inline typename CAtlHttpClientT<TSocketClass>::CHUNK_LEX_RESULT CAtlHttpClientT<TSocketClass>::consume_chunk_trailer(char *&pBufferStart, char *pBufferEnd)\r
1736         CHUNK_LEX_RESULT result = LEX_ERROR;\r
1737         if (pBufferStart >= pBufferEnd)\r
1738                 return result;\r
1740         char *pHeaderEnd = NULL;\r
1741         char *pTemp = pBufferStart;\r
1742         // check for empty trailer, this means there are no more trailers\r
1743         if ( (pTemp < pBufferEnd && *pTemp == '\r') &&\r
1744                         (pTemp+1 < pBufferEnd && *(pTemp+1) == '\n'))\r
1745         {\r
1746                 pBufferStart += 2;\r
1747                 return LEX_TRAILER_COMPLETE;\r
1748         }\r
1750         while (pTemp <= pBufferEnd)\r
1751         {\r
1752                 if ( (pTemp < pBufferEnd && *pTemp == '\r') &&\r
1753                          (pTemp+1 < pBufferEnd && *(pTemp+1) == '\n'))\r
1754                 {\r
1755                          pHeaderEnd = pTemp; // success case\r
1756                          result = LEX_OK;\r
1757                          break;\r
1758                 }\r
1759                 pTemp++;\r
1760         }\r
1762         if (result == LEX_OK)\r
1763         {\r
1764                 DecodeHeader(pBufferStart, pHeaderEnd);\r
1765                 pBufferStart = pHeaderEnd + 2;\r
1766         }\r
1767         else if (result != LEX_OK &&\r
1768                 pTemp > pBufferEnd)\r
1769                 result = LEX_OUTOFDATA;\r
1770         return result;\r
1773 template<class TSocketClass>\r
1774 inline typename CAtlHttpClientT<TSocketClass>::CHUNK_LEX_RESULT CAtlHttpClientT<TSocketClass>::consume_chunk_footer(char *&pBufferStart, char *&pBufferEnd)\r
1776         CHUNK_LEX_RESULT result = LEX_ERROR;\r
1777         if (pBufferStart < pBufferEnd &&\r
1778                 (pBufferStart+1) <= pBufferEnd)\r
1779         {\r
1780                 if ( *pBufferStart == '\r' &&   \r
1781                          *(pBufferStart+1) == '\n')\r
1782                 {\r
1783                         pBufferStart += 2;\r
1784                         result = LEX_OK;\r
1785                 }\r
1786         }\r
1787         else\r
1788                 result = LEX_OUTOFDATA;\r
1789         return result;\r
1792 #define CHUNK_BUFF_SIZE 2048\r
1794 template<class TSocketClass>\r
1795 inline bool CAtlHttpClientT<TSocketClass>::ReadChunkedBody() throw()\r
1797         // At this point, m_current contains the headers, up to and including the \r\n\r\n,\r
1798         // plus any additional data that might have been read off the socket. So, we need\r
1799         // to copy off the additional data into our read buffer before we start parsing the\r
1800         // chunks.\r
1801 #ifdef _DEBUG\r
1802         // nReadCount, keeps track of how many socket reads we do.\r
1803         int nReadCount = 0;\r
1804 #endif\r
1806         // nChunkBuffCarryOver\r
1807         // When we run out of data in the input buffer, this is the\r
1808         // count of bytes that are left in the input that could not\r
1809         // be lexed into anything useful. We copy this many bytes to\r
1810         // the top of the input buffer before we fill the input buffer\r
1811         // with more bytes from the socket\r
1812         long nChunkBuffCarryOver = 0;\r
1814         // nChunkSize\r
1815         // The size of the next chunk to be read from the input buffer.\r
1816         long nChunkSize = 0;\r
1818         // t_chunk_buffer\r
1819         // The heap allocated buffer that we holds data\r
1820         // read from the socket. We will increase the size\r
1821         // of this buffer to 2 times the max chunk size we\r
1822         // need to read if we have to.\r
1823         CHeapPtr<char> t_chunk_buffer;\r
1825         // nTChunkBuffSize\r
1826         // Keeps track of the allocated size of t_chunk_buffer.\r
1827         // This size will change if we need to read chunks bigger\r
1828         // than the currently allocated size of t_chunk_buffer.\r
1829         long nTChunkBuffSize = CHUNK_BUFF_SIZE;\r
1831         // chunk_buffer & chunk_buffer_end\r
1832         // Keeps track of the current location\r
1833         // in t_chunk_buffer that we are lexing input from.\r
1834         // chunk_buffer_end is the end of the input buffer we\r
1835         // are lexing from. chunk_buffer_end is used as a marker\r
1836         // to make sure we don't read past the end of our input buffer\r
1837         char *chunk_buffer, *chunk_buffer_end;\r
1839         // cstate\r
1840         // The current state of the chunk parsing state machine. We\r
1841         // start out reading the size of the first chunk.\r
1842         CHUNK_STATE cstate = READ_CHUNK_SIZE;\r
1844         // cresult\r
1845         // Holds the value of the result of a lexing operation performed\r
1846         // on the input buffer.\r
1847         CHUNK_LEX_RESULT cresult = LEX_OK;\r
1849         CAtlIsapiBuffer<> result_buffer;\r
1851         // Initialize pointers and allocate the chunk buffer.\r
1852         chunk_buffer = chunk_buffer_end = NULL;\r
1853         if( !t_chunk_buffer.Allocate(nTChunkBuffSize) )\r
1854                 return false;\r
1856         // copy the headers into a temporary buffer.\r
1857         result_buffer.Append(m_current + m_dwHeaderStart, m_dwHeaderLen);\r
1859         // calculate number of bytes left in m_current past the headers\r
1860         long leftover_in_m_current = m_current.GetLength() - (m_dwHeaderStart + m_dwHeaderLen);\r
1862         // copy the extra bytes that might have been read into m_current into the chunk buffer\r
1863         if (leftover_in_m_current > 0)\r
1864         {\r
1865                 if (leftover_in_m_current > nTChunkBuffSize)\r
1866                 {\r
1867                         if( ! t_chunk_buffer.Reallocate(leftover_in_m_current) )\r
1868                                 return false;\r
1869                 }\r
1871                 chunk_buffer = (char*)t_chunk_buffer;\r
1872                 Checked::memcpy_s(chunk_buffer, leftover_in_m_current, ((LPCSTR)m_current)+ m_dwHeaderStart + m_dwHeaderLen, leftover_in_m_current);\r
1873                 chunk_buffer_end = chunk_buffer + leftover_in_m_current;\r
1874         }\r
1876         m_current.Empty();\r
1877         m_dwBodyLen = 0;\r
1878         m_dwHeaderStart = 0;\r
1880         // as we start the state machine, we should be either pointing at the first\r
1881         // byte of chunked response or nothing, in which case we will need to get \r
1882         // more data from the socket.\r
1883         nChunkSize = 0;\r
1885         bool bDone = false;\r
1887         while(!bDone)\r
1888         {\r
1889                 // if we run out of data during processing, chunk_buffer\r
1890                 // get set to null\r
1891                 if (!chunk_buffer ||\r
1892                         chunk_buffer >= chunk_buffer_end)\r
1893                 {\r
1894                         // we ran out of data in our input buffer, we need\r
1895                         // to read more from the socket.\r
1896                         DWORD dwReadBuffSize = nTChunkBuffSize - nChunkBuffCarryOver;\r
1897                         chunk_buffer = t_chunk_buffer;\r
1898                         if (!Read((const unsigned char*)(chunk_buffer+nChunkBuffCarryOver), &dwReadBuffSize))\r
1899                         {\r
1900                                 ATLTRACE("ReadChunkedBody: Error reading from socket (%d)\n", GetLastError());\r
1901                                 return false;\r
1902                         }\r
1903                         else if(dwReadBuffSize == 0)\r
1904                         {\r
1905                                 ATLTRACE("ReadChunkedBody: The socket read timed out and no bytes were read from the socket.\n");\r
1906                                 return false;\r
1907                         }\r
1908 #ifdef _DEBUG\r
1909                         ATLTRACE("ReadChunkedBody read %d bytes from socket. Reads %d \n", dwReadBuffSize, ++nReadCount);\r
1910 #endif\r
1911                         chunk_buffer_end = chunk_buffer + nChunkBuffCarryOver + dwReadBuffSize;\r
1912                         nChunkBuffCarryOver = 0;\r
1913                 }\r
1915                 switch(cstate)\r
1916                 {\r
1917                 case READ_CHUNK_SIZE:\r
1918                         {\r
1919                                 cresult = get_chunked_size(chunk_buffer, chunk_buffer_end, &nChunkSize);\r
1920                                 switch(cresult)\r
1921                                 {\r
1922                                 case LEX_ERROR:\r
1923                                         ATLTRACE("ReadChunkedBody Failed retrieving chunk size\n");\r
1924                                         return false;\r
1925                                         break;\r
1926                                 case LEX_OUTOFDATA:\r
1927                                         nChunkBuffCarryOver = (long)(chunk_buffer_end - chunk_buffer);\r
1928                                         if (!move_leftover_bytes((char*)t_chunk_buffer, nChunkBuffCarryOver, \r
1929                                                                                 chunk_buffer, chunk_buffer_end))\r
1930                                         {\r
1931                                                 ATLTRACE("failed to move leftover chunk data to head of buffer\n");\r
1932                                                 return false;\r
1933                                         }\r
1934                                         chunk_buffer = chunk_buffer_end = NULL;\r
1935                                         break;\r
1936                                 case LEX_OK:\r
1937                                         if (nChunkSize == 0)\r
1938                                         {\r
1939                                                 cstate = CHUNK_READ_DATA_COMPLETE;\r
1940                                         }\r
1941                                         else if (nChunkSize + 2 > nTChunkBuffSize)\r
1942                                         {\r
1943                                                 char *pBuffStart = (char*)t_chunk_buffer;\r
1944                                                 int nReadSoFar = (int)(chunk_buffer - pBuffStart);\r
1945                                                 int nTotal = (int)(chunk_buffer_end - pBuffStart);                      \r
1946                                                 if( FAILED(::ATL::AtlMultiply(&nTChunkBuffSize, nChunkSize, 2L)))\r
1947                                                 {\r
1948                                                         return false;\r
1949                                                 }\r
1950                                                 t_chunk_buffer.Reallocate(nTChunkBuffSize);\r
1951                                                 pBuffStart = (char*)t_chunk_buffer;\r
1952                                                 chunk_buffer = pBuffStart + nReadSoFar;\r
1953                                                 chunk_buffer_end = pBuffStart + nTotal;\r
1954                                                 cstate = READ_CHUNK_SIZE_FOOTER;\r
1955                                                 m_dwBodyLen += nChunkSize;\r
1956                                         }\r
1957                                         else\r
1958                                         {\r
1959                                                 // everything is OK. move to next state\r
1960                                                 cstate = READ_CHUNK_SIZE_FOOTER;\r
1961                                                 m_dwBodyLen += nChunkSize;\r
1962                                         }\r
1963                                         break;\r
1964                                 default:\r
1965                                         ATLASSERT(0);\r
1966                                         return false;\r
1967                                         break;\r
1968                                 }\r
1969                         }\r
1970                         break;\r
1971                 case READ_CHUNK_DATA:\r
1972                         {\r
1973                                 char *pDataStart = NULL;\r
1974                                 long nDataLen = 0;\r
1975                                 cresult = LEX_OK;\r
1976                                 cresult = get_chunked_data(chunk_buffer, chunk_buffer_end,\r
1977                                                                                         nChunkSize, &pDataStart, &nDataLen);\r
1978                                 switch(cresult)\r
1979                                 {\r
1980                                 case LEX_ERROR:\r
1981                                         ATLTRACE("ReadChunkedBody failed to retrieve chunk data\n");\r
1982                                         return false;\r
1983                                         break;\r
1984                                 case LEX_OUTOFDATA:\r
1985                                         nChunkBuffCarryOver = (long)(chunk_buffer_end - chunk_buffer);\r
1986                                         if (!move_leftover_bytes((char*)t_chunk_buffer, nChunkBuffCarryOver, \r
1987                                                                                 chunk_buffer, chunk_buffer_end))\r
1988                                         {\r
1989                                                 ATLTRACE("failed to move leftover chunk data to head of buffer\n");\r
1990                                                 return false;\r
1991                                         }\r
1992                                         chunk_buffer = chunk_buffer_end = NULL;\r
1993                                         break;\r
1994                                 case LEX_OK:\r
1995                                         result_buffer.Append(pDataStart, nDataLen);\r
1996                                         cstate = READ_CHUNK_DATA_FOOTER;\r
1997                                         break;\r
1998                                 default:\r
1999                                         ATLASSERT(0);\r
2000                                         return false;\r
2001                                 }\r
2002                         }\r
2003                         break;\r
2004                         case READ_CHUNK_SIZE_FOOTER:\r
2005                         case READ_CHUNK_DATA_FOOTER:\r
2006                         {\r
2007                                 cresult = consume_chunk_footer(chunk_buffer, chunk_buffer_end);\r
2008                                 switch(cresult)\r
2009                                 {\r
2010                                 case LEX_OK:\r
2011                                         cstate = (cstate == READ_CHUNK_SIZE_FOOTER) ? READ_CHUNK_DATA : READ_CHUNK_SIZE;\r
2012                                         break;\r
2013                                 case LEX_ERROR:\r
2014                                         ATLTRACE("Error consuming chunk footer!\n");\r
2015                                         return false;\r
2016                                         break;\r
2017                                 case LEX_OUTOFDATA:\r
2018                                         nChunkBuffCarryOver = (long)(chunk_buffer_end - chunk_buffer);\r
2019                                         if (!move_leftover_bytes((char*)t_chunk_buffer, nChunkBuffCarryOver, \r
2020                                                                                 chunk_buffer, chunk_buffer_end))\r
2021                                         {\r
2022                                                 ATLTRACE("failed to move leftover chunk data to head of buffer\n");\r
2023                                                 return false;\r
2024                                         }\r
2025                                         chunk_buffer = chunk_buffer_end = NULL;\r
2026                                         break;\r
2027                                 default:\r
2028                                         ATLASSERT(0);\r
2029                                         return false;\r
2031                                 }\r
2032                         }\r
2033                         break;\r
2034                         case CHUNK_READ_DATA_COMPLETE:\r
2035                         {\r
2036                                 // We read the chunk of size 0\r
2037                                 // consume the chunk footer.\r
2038                                 DWORD dwLen = 0;\r
2039                                 cresult = consume_chunk_footer(chunk_buffer, chunk_buffer_end);\r
2040                                 if (GetHeaderValue((_T("Trailer")), NULL, &dwLen))\r
2041                                 {\r
2042                                         cstate = READ_CHUNK_TRAILER; // start reading trailer headers\r
2043                                         break;\r
2044                                 }\r
2045                                 else\r
2046                                         bDone = true;\r
2047                         }\r
2048                         break;\r
2049                         case READ_CHUNK_TRAILER:\r
2050                                 cresult = consume_chunk_trailer(chunk_buffer, chunk_buffer_end);\r
2051                                 switch(cresult)\r
2052                                 {\r
2053                                 case LEX_OK:\r
2054                                         cstate = READ_CHUNK_TRAILER; // keep reading\r
2055                                         break;\r
2056                                 case LEX_ERROR:\r
2057                                         ATLTRACE("Error consuming chunk trailers!\n");\r
2058                                         return false;\r
2059                                         break;\r
2060                                 case LEX_OUTOFDATA:\r
2061                                         nChunkBuffCarryOver = (long)(chunk_buffer_end - chunk_buffer);\r
2062                                         if (!move_leftover_bytes((char*)t_chunk_buffer, nChunkBuffCarryOver, \r
2063                                                                                 chunk_buffer, chunk_buffer_end))\r
2064                                         {\r
2065                                                 ATLTRACE("failed to move leftover chunk data to head of buffer\n");\r
2066                                                 return false;\r
2067                                         }\r
2068                                         chunk_buffer = chunk_buffer_end = NULL;\r
2069                                         break;\r
2070                                 case LEX_TRAILER_COMPLETE:\r
2071                                         return true;\r
2072                                         break;\r
2073                                 default:\r
2074                                         ATLASSERT(0);\r
2075                                         return false;\r
2079                                 }\r
2080                                 break;\r
2082                 }\r
2083         }\r
2084         if (!m_current.Append((LPCSTR)result_buffer))\r
2085                 return false;\r
2086                 \r
2087         m_pEnd = ((BYTE*)(LPCSTR)m_current) + m_current.GetLength();\r
2088         \r
2089         return true;\r
2092 template<class TSocketClass>\r
2093 inline bool CAtlHttpClientT<TSocketClass>::ReconnectIfRequired() throw()\r
2095         CString strValue;\r
2096         // if we have a keep-alive header then return true\r
2097         // else we have to close and re-open the connection\r
2098         if (GetHeaderValue(_T("Connection"), strValue))\r
2099         {\r
2100                 if (!strValue.CompareNoCase(_T("keep-alive")))\r
2101                         return true; // server said keep connection open.\r
2102         }\r
2103         else\r
2104         {\r
2105                 return true; // there was no 'Connection' header\r
2106         }\r
2108         if (!strValue.CompareNoCase(_T("close")))\r
2109         {\r
2110                 Close();\r
2111                 ConnectSocket();\r
2112         }   \r
2113         return false;\r
2116 // Complete relative URLs and URLs\r
2117 // that have a missing path. These are common with redirect headers.\r
2118 // http://www.microsoft.com becomes http://www.microsoft.com/\r
2119 // localstart.asp becomes whatever our current (m_urlCurrent) \r
2120 // path is plus localstart.asp\r
2121 template<class TSocketClass>\r
2122 inline bool CAtlHttpClientT<TSocketClass>::CompleteURL(CString& strURL) throw()\r
2124         _ATLTRY\r
2125         {\r
2126                 CString strUrlTemp = strURL;\r
2127                 strUrlTemp.Trim();\r
2128                 CUrl url;\r
2129                 bool bErr = false;\r
2130                 if (url.CrackUrl(strUrlTemp))\r
2131                 {\r
2132                         return true; // URL is already valid\r
2133                 }\r
2136                 // if we have a scheme and a host name but no\r
2137                 // path, then add the path of '/'\r
2138                 if (url.GetScheme() == ATL_URL_SCHEME_HTTP &&\r
2139                         url.GetHostNameLength() > 0 &&\r
2140                         !url.GetUrlPathLength() )\r
2141                 {\r
2142                         url.SetUrlPath(_T("/"));\r
2143                         bErr = true;\r
2144                 } \r
2145                 // if we have leading / (absolute path) (ex: /Test/bbb.asp) we can concatinate it \r
2146                 // to it to our current URL (m_urlCurrent) scheme and host              \r
2147                 else if (strUrlTemp[0] ==  _T('/'))\r
2148                 {\r
2149                         url = m_urlCurrent;\r
2150                         url.SetUrlPath(strUrlTemp);\r
2151                         bErr = true;\r
2152                 }\r
2153                 // relative path (ex: bbb.asp) - we don't have a valid url\r
2154                 // and the first char is not /\r
2155                 // Get the url from our current URL (m_urlCurrent) and add\r
2156                 // our relative paths\r
2157                 else\r
2158                 {\r
2159                         CString szPath;\r
2160                         url = m_urlCurrent;\r
2162                         if (!url.GetUrlPathLength())\r
2163                         {\r
2164                                 szPath = _T('/'); // current URL has no path!\r
2165                         }\r
2166                         else\r
2167                         {\r
2168                                 szPath = url.GetUrlPath();\r
2169                         }\r
2170                                 \r
2171                         // back up to the first / and insert our current url\r
2172                         int pos = szPath.ReverseFind(_T('/'));\r
2173                         if(pos == -1)\r
2174                         {\r
2175                                 return false;\r
2176                         }\r
2177                                 \r
2178                         szPath.GetBufferSetLength(pos+1);\r
2179                         szPath.ReleaseBuffer();\r
2181                         szPath += strURL;\r
2182                         url.SetUrlPath(szPath);\r
2183                         bErr = true;\r
2184                 }\r
2185                 if (!bErr)\r
2186                 {\r
2187                         return bErr;\r
2188                 }\r
2189                 DWORD dwLen = ATL_URL_MAX_PATH_LENGTH;\r
2191                 return url.CreateUrl(strURL.GetBuffer(ATL_URL_MAX_PATH_LENGTH),\r
2192                         &dwLen) ? true : false;\r
2193         }\r
2194         _ATLCATCHALL()\r
2195         {\r
2196                 return false;\r
2197         }\r
2200 template<class TSocketClass>\r
2201 inline bool CAtlHttpClientT<TSocketClass>::ProcessObjectMoved() throw()\r
2203         _ATLTRY\r
2204         {\r
2205                 // look for a location header\r
2206                 CString strValue;\r
2207                 CString strURLNew;\r
2208                 if (GetHeaderValue(_T("Location"), strValue))\r
2209                 {                       \r
2210                         CString strRedirectReqHeaders=m_pNavData->szExtraHeaders;       \r
2211                         ReconnectIfRequired();\r
2212                         m_HeaderMap.RemoveAll();\r
2213                         m_current.Empty();\r
2216                         // create a new URL based on what is in the\r
2217                         // Location header and set it as this object's \r
2218                         // default Url\r
2219                         strURLNew = strValue;\r
2220                         CompleteURL(strURLNew);\r
2221                         CString strCurrHostName = m_urlCurrent.GetHostName();\r
2222                         ATL_URL_PORT nCurrPort=m_urlCurrent.GetPortNumber();\r
2223                          \r
2224                         SetDefaultUrl((LPCTSTR)strURLNew, m_urlCurrent.GetPortNumber());\r
2225                         //If redirected (new url in strURLNew) to different host (server) or port, need a new socket.\r
2226                         if (m_urlCurrent.GetHostName()!=strCurrHostName || m_urlCurrent.GetPortNumber()!=nCurrPort)\r
2227                         {\r
2228                                 Close();\r
2229                                 ConnectSocket();\r
2230                         }\r
2231                         // build up a request.                  \r
2232                         CString strRequest;\r
2233                         BuildRequest(&strRequest,\r
2234                                                 m_strMethod,\r
2235                                                 strRedirectReqHeaders.GetString());\r
2237                         // send the request\r
2238                         DWORD dwSent = strRequest.GetLength();\r
2239                         DWORD dwAvailable = dwSent;\r
2240                         if (!Write((BYTE*)((LPCSTR)CT2A(strRequest.GetBuffer(dwAvailable))), &dwSent))\r
2241                                 return false;\r
2242                         strRequest.ReleaseBuffer();\r
2244                         if (dwSent != dwAvailable)\r
2245                                 return false;\r
2247                         // read the response\r
2248                         if (RR_OK == ReadHttpResponse())\r
2249                         {\r
2250                                 if (m_pNavData)\r
2251                                         ProcessStatus(m_pNavData->dwFlags);\r
2252                         }\r
2253                 }\r
2254                 return true;\r
2255         }\r
2256         _ATLCATCHALL()\r
2257         {\r
2258                 return false;\r
2259         }\r
2262 template<class TSocketClass>\r
2263 inline bool CAtlHttpClientT<TSocketClass>::_SetDefaultUrl(LPCTSTR szURL, short nPort) throw()\r
2266         if (szURL)\r
2267                 if (!m_urlCurrent.CrackUrl(szURL)) // re-inits the field of the CUrl first\r
2268                         return false;\r
2270         ATL_URL_SCHEME currScheme = m_urlCurrent.GetScheme();\r
2271         if ( currScheme != ATL_URL_SCHEME_HTTP &&\r
2272                  !TSocketClass::SupportsScheme(currScheme) )\r
2273                 return false; // only support HTTP\r
2275         if (!m_urlCurrent.GetUrlPathLength())\r
2276         {\r
2277                 // no path, default to /\r
2278                 m_urlCurrent.SetUrlPath(_T("/"));\r
2279         }\r
2281         if (!m_urlCurrent.GetHostNameLength())\r
2282         {\r
2283                 // no server name\r
2284                 return false;\r
2285         }\r
2287         if (m_urlCurrent.GetPortNumber() == ATL_URL_INVALID_PORT_NUMBER)\r
2288                 m_urlCurrent.SetPortNumber(nPort);\r
2289         return true;\r
2292 template<class TSocketClass>\r
2293 inline int CAtlHttpClientT<TSocketClass>::GetStatus() throw()\r
2295         return m_nStatus;\r
2298 template<class TSocketClass>\r
2299 inline LPCTSTR CAtlHttpClientT<TSocketClass>::GetMethod() throw()\r
2301         return m_strMethod;\r
2304 template<class TSocketClass>\r
2305 inline BYTE* CAtlHttpClientT<TSocketClass>::GetPostData() throw()\r
2307         if (m_pNavData)\r
2308                 return m_pNavData->pData;\r
2309         return NULL;\r
2312 template<class TSocketClass>\r
2313 inline DWORD CAtlHttpClientT<TSocketClass>::GetPostDataLen() throw()\r
2315         if (m_pNavData)\r
2316                 return m_pNavData->dwDataLen;\r
2317         return 0;\r
2320 template<class TSocketClass>\r
2321 inline LPCTSTR CAtlHttpClientT<TSocketClass>::GetPostDataType() throw()\r
2323         if (m_pNavData)\r
2324                 return m_pNavData->szDataType;\r
2325         return NULL;\r
2328 template<class TSocketClass>\r
2329 inline DWORD CAtlHttpClientT<TSocketClass>::GetLastError() throw()\r
2331         return m_dwLastError;\r
2334 template<class TSocketClass>\r
2335 inline const SOCKET& CAtlHttpClientT<TSocketClass>::GetSocket() throw()\r
2337         return const_cast<const SOCKET&>(m_socket);\r
2340 template<class TSocketClass>\r
2341 inline void CAtlHttpClientT<TSocketClass>::Close() throw()\r
2343         TSocketClass::Close();\r
2346 template<class TSocketClass>\r
2347 inline DWORD CAtlHttpClientT<TSocketClass>::SetSocketTimeout(DWORD dwNewTimeout) throw()\r
2349         return TSocketClass::SetSocketTimeout(dwNewTimeout);\r
2352 template<class TSocketClass>\r
2353 inline DWORD CAtlHttpClientT<TSocketClass>::GetSocketTimeout() throw()\r
2355         return TSocketClass::GetSocketTimeout();\r
2358 template<class TSocketClass>\r
2359 inline void CAtlHttpClientT<TSocketClass>::AuthProtocolFailed(LPCTSTR szProto) throw()\r
2361         CAtlBaseAuthObject *pAuthObj = NULL;\r
2362         _ATLTRY\r
2363         {\r
2364                 if (m_AuthMap.Lookup(szProto, pAuthObj) && pAuthObj)\r
2365                 {\r
2366                         pAuthObj->m_bFailed = true;\r
2367                 }\r
2368         }\r
2369         _ATLCATCHALL()\r
2370         {\r
2371         }\r
2374 template<class TSocketClass>\r
2375 inline const ATL_NAVIGATE_DATA* CAtlHttpClientT<TSocketClass>::GetCurrentNavdata()\r
2377         return m_pNavData;\r
2381 /////////////////////////////////////////////////////////////////////////////////\r
2382 //\r
2383 // CNTLMAuthObject\r
2384 // NTLM Security Authorization functions \r
2385 //\r
2386 /////////////////////////////////////////////////////////////////////////////////\r
2387 inline CNTLMAuthObject::CNTLMAuthObject() throw() :\r
2388         m_pSocket(NULL),\r
2389         m_nMaxTokenSize(0),\r
2390         m_pAuthInfo(NULL),\r
2391         m_bProxy(false)\r
2393         SecInvalidateHandle(&m_hCredentials)\r
2396 inline CNTLMAuthObject::CNTLMAuthObject(IAuthInfo *pAuthInfo) throw() :\r
2397         m_pSocket(NULL),\r
2398         m_nMaxTokenSize(0),\r
2399         m_pAuthInfo(pAuthInfo)\r
2401         SecInvalidateHandle(&m_hCredentials)\r
2404 inline CNTLMAuthObject::~CNTLMAuthObject() throw()\r
2406         if (!ATL_IS_INVALIDCREDHANDLE(m_hCredentials))\r
2407                 FreeCredentialsHandle(&m_hCredentials);\r
2410 inline void CNTLMAuthObject::Init(CAtlHttpClient *pSocket, IAuthInfo *pAuthInfo) throw()\r
2412         m_pSocket = pSocket;\r
2413         SetAuthInfo(pAuthInfo);\r
2416 inline void CNTLMAuthObject::SetAuthInfo(IAuthInfo *pAuthInfo) throw()\r
2418         m_pAuthInfo = pAuthInfo;\r
2421 inline bool CNTLMAuthObject::Authenticate(LPCTSTR /*szAuthTypes*/, bool bProxy) throw()\r
2423         m_bProxy = bProxy;\r
2424         if (AcquireCredHandle())\r
2425                 return DoNTLMAuthenticate();\r
2426         return false;\r
2429 inline bool CNTLMAuthObject::AcquireCredHandle() throw()\r
2431         PSecPkgInfo pPackageInfo = NULL;\r
2432         SECURITY_STATUS SecurityStatus = SEC_E_OK;\r
2434         // Acquire a credentials handle on the NTLM security package\r
2435         SecurityStatus = QuerySecurityPackageInfo(ATL_HTTP_AUTHTYPE_NTLM,\r
2436                                                         &pPackageInfo);\r
2438         if (SecurityStatus != SEC_E_OK)\r
2439                 return false;\r
2441         void *pAuthData = NULL;\r
2442         CSecAuthIdentity CA;\r
2443         if (m_pAuthInfo)\r
2444         {\r
2445                 // if m_pAuthInfo has been set then the caller wants us\r
2446                 // to get credentials from them.\r
2447                 if (CA.Init(m_pAuthInfo))\r
2448                         pAuthData = static_cast<void*>(&CA);\r
2449         }\r
2451         SecurityStatus = AcquireCredentialsHandle(\r
2452                                         0,\r
2453                                         pPackageInfo->Name,\r
2454                                         SECPKG_CRED_OUTBOUND,\r
2455                                         0,\r
2456                                         pAuthData,\r
2457                                         0,\r
2458                                         0,\r
2459                                         &m_hCredentials,\r
2460                                         &m_ts\r
2461                                         );\r
2463         m_nMaxTokenSize = pPackageInfo->cbMaxToken;\r
2464         FreeContextBuffer(pPackageInfo);\r
2465         return SecurityStatus == SEC_E_OK ? true : false;\r
2468 inline bool CNTLMAuthObject::DoNTLMAuthenticate() throw()\r
2470         bool bRet = false;\r
2471                                                 \r
2472         m_CurrentRequestData = (*(const_cast<const ATL_NAVIGATE_DATA*>(m_pSocket->GetCurrentNavdata())));\r
2473         // make sure we have a good credentials handle\r
2474         ATLASSERT(!ATL_IS_INVALIDCREDHANDLE(m_hCredentials));\r
2475         if (ATL_IS_INVALIDCREDHANDLE(m_hCredentials))\r
2476                 return false;\r
2478         SECURITY_STATUS SecurityStatus = SEC_E_OK;\r
2480         unsigned long ContextAttributes = 0;\r
2481         CSecBufferDesc OutBufferDesc;\r
2482         CtxtHandle SecurityContext;\r
2483         SecInvalidateHandle(&SecurityContext);\r
2485         // Create a SecBufferDesc with one buffer of m_nMaxTokenSize\r
2486         if (!OutBufferDesc.AddBuffers(1, m_nMaxTokenSize))\r
2487                 return false;\r
2489         SecurityStatus = InitializeSecurityContext(\r
2490                                 &m_hCredentials,\r
2491                                 0,\r
2492                                 NULL,                   \r
2493                                 ISC_REQ_CONNECTION,\r
2494                                 0,\r
2495                                 0,\r
2496                                 0,\r
2497                                 0,\r
2498                                 &SecurityContext,\r
2499                                 OutBufferDesc,\r
2500                                 &ContextAttributes,\r
2501                                 &m_ts\r
2502                                 );\r
2504         if ( (SecurityStatus == SEC_I_COMPLETE_NEEDED) ||\r
2505                  (SecurityStatus == SEC_I_COMPLETE_AND_CONTINUE) )\r
2506         {\r
2507                 SecurityStatus = CompleteAuthToken( &SecurityContext, (PSecBufferDesc)OutBufferDesc);\r
2508         }\r
2510         if (IS_ERROR(SecurityStatus))\r
2511                 return false;\r
2513         // create an Authentication header with the contents of the\r
2514         // security buffer and send it to the HTTP server. The output\r
2515         // buffer will be pointing to a buffer that contains the \r
2516         // response from the HTTP server on return.\r
2517         LPSTR pszbuff = NULL;\r
2518         if (!SendSecurityInfo(OutBufferDesc.Buffers(0), &pszbuff) || !pszbuff)\r
2519                 return false;\r
2521         CString strVal;\r
2522         if (!m_pSocket->GetHeaderValue(m_bProxy ? g_pszProxyAuthenticate : g_pszWWWAuthenticate, strVal))\r
2523                 return false; // wrong authentication type\r
2525         LPCTSTR szResponsecode = strVal;\r
2526         TCHAR pszcode[ATL_AUTH_HDR_SIZE];\r
2527         if (szResponsecode)\r
2528         {\r
2529                 // first four characters better be 'NTLM'\r
2530                 if (_tcsncicmp(szResponsecode, _T("NTLM"), 4) != 0)\r
2531                         return false;\r
2533                 // skip NTLM\r
2534                 szResponsecode += 4;\r
2536                 // skip space\r
2537                 while (*szResponsecode && _AtlIsHttpSpace(*szResponsecode))\r
2538                         szResponsecode++;\r
2540                 // find end of header\r
2541                 LPCTSTR pszend = szResponsecode;\r
2542                 while (*pszend && *pszend != _T('\r'))\r
2543                         pszend++;\r
2544                 bRet = false;\r
2545                 if (pszend)\r
2546                 {\r
2547                         // copy authentication data to our buffer\r
2548                         // and base64decode it.\r
2549                         int nlen = (int)(pszend-szResponsecode);\r
2550                         Checked::memcpy_s(pszcode, ATL_AUTH_HDR_SIZE, szResponsecode, nlen*sizeof(TCHAR));\r
2551                         pszcode[pszend-szResponsecode]=0;\r
2553                         // re-use OutBufferDesc here since we'll need to need\r
2554                         // a SecBufferDesc to pass to the next call to InitializeSecurityContext\r
2555                         // anyways.\r
2556                         if(!OutBufferDesc.Buffers(0)->ClearBuffer(m_nMaxTokenSize))\r
2557                                 return false;\r
2558                                 \r
2559                         _ATLTRY\r
2560                         {\r
2561                                 CT2A pszcode_a(pszcode);\r
2562                                 bRet = Base64Decode(pszcode_a,\r
2563                                                                         (int) strlen(pszcode_a), \r
2564                                                                         (BYTE*)OutBufferDesc.Buffers(0)->pvBuffer,\r
2565                                                                         (int*) &OutBufferDesc.Buffers(0)->cbBuffer) != FALSE;\r
2566                         }\r
2567                         _ATLCATCHALL()\r
2568                         {\r
2569                                 bRet = false;\r
2570                         }\r
2571                 }\r
2573                 if (!bRet)\r
2574                         return false;\r
2576                 // Create buffers for the challenge data\r
2577                 CSecBufferDesc *InBufferDesc = &OutBufferDesc;\r
2578                 CSecBufferDesc OutBufferDesc2;\r
2579                 if (!OutBufferDesc2.AddBuffers(1, m_nMaxTokenSize))\r
2580                         return false;\r
2582                 // Process the challenge response from the server\r
2583                 SecurityStatus = InitializeSecurityContext(\r
2584                                         0,\r
2585                                         &SecurityContext,\r
2586                                         NULL,\r
2587                                         0,\r
2588                                         0,\r
2589                                         0 ,\r
2590                                         InBufferDesc,\r
2591                                         0,\r
2592                                         &SecurityContext,\r
2593                                         OutBufferDesc2,\r
2594                                         &ContextAttributes,\r
2595                                         &m_ts\r
2596                                         );\r
2598                 if (IS_ERROR(SecurityStatus))\r
2599                         return false;\r
2601                 pszbuff = NULL;\r
2602                 if (SendSecurityInfo(OutBufferDesc2.Buffers(0), &pszbuff))\r
2603                 {\r
2604                         // at this point we should be authenticated and either have the page\r
2605                         // we requested or be getting re-directed to another page under our\r
2606                         // authorization. Either way, we don't want to go through authorization\r
2607                         // code again if we are not authorized to prevent recursive authorization\r
2608                         // so we tell the client not to try this protocol again.\r
2609                         if (m_pSocket->GetStatus() == 401 ||\r
2610                                 m_pSocket->GetStatus() == 407)\r
2611                         {\r
2612                                 // Authorization with this protocol failed.\r
2613                                 // don't try it again.\r
2614                                 m_pSocket->AuthProtocolFailed(_T("NTLM"));\r
2615                         }\r
2616                         bRet = m_pSocket->ProcessStatus(m_pSocket->GetFlags());\r
2617                 }\r
2618         }\r
2620         return bRet;\r
2622 inline bool CNTLMAuthObject::GetCredentialNames(CString& theName)\r
2624         if (ATL_IS_INVALIDCREDHANDLE(m_hCredentials))\r
2625                 return false;\r
2627         SecPkgCredentials_Names spcn;\r
2628         if(!IS_ERROR(QueryCredentialsAttributes(&m_hCredentials, \r
2629                 SECPKG_CRED_ATTR_NAMES, (void*)&spcn)))\r
2630         {\r
2631                 theName = spcn.sUserName;\r
2632                 return true;\r
2633         }\r
2634         return false;\r
2637 inline bool CNTLMAuthObject::SendSecurityInfo(SecBuffer *pSecBuffer, LPSTR *pszBuffer) throw()\r
2639         ATLASSERT(pSecBuffer);\r
2640         ATLASSUME(m_pSocket);\r
2641         ATLASSERT(pszBuffer);\r
2643         int nDest = ATL_AUTH_HDR_SIZE;\r
2644         char auth_b64encoded[ATL_AUTH_HDR_SIZE];\r
2645         char auth_header[ATL_AUTH_HDR_SIZE];\r
2646         const char *pszFmtStr = m_bProxy ? m_pszFmtProxy : m_pszFmtWWW;\r
2648         if (!pSecBuffer || !pSecBuffer->pvBuffer || !pszBuffer)\r
2649                 return false;\r
2650         *pszBuffer = 0;\r
2652         // Base64Encode will fail gracefully if buffer not big enough\r
2653         if (Base64Encode((BYTE*)pSecBuffer->pvBuffer, pSecBuffer->cbBuffer,\r
2654                 auth_b64encoded, &nDest, ATL_BASE64_FLAG_NOCRLF))\r
2655         {\r
2656                 if (nDest < ATL_AUTH_HDR_SIZE)\r
2657                 {\r
2658                         auth_b64encoded[nDest]=0;\r
2659                         // make sure we have enough room in our header buffer\r
2660                         if ( (strlen(pszFmtStr)-2 + nDest) < ATL_AUTH_HDR_SIZE)\r
2661                                 sprintf_s(auth_header, ATL_AUTH_HDR_SIZE, pszFmtStr, auth_b64encoded);\r
2662                         else\r
2663                                 return false;\r
2664                 }\r
2665                 else\r
2666                         return false;\r
2667         }\r
2668         else\r
2669                 return false;\r
2671         // reset the connection if required\r
2672         m_pSocket->ResetConnection();\r
2674         // Resend the request with the authorization information\r
2675         LPCURL pUrl = m_pSocket->GetCurrentUrl();   \r
2676         bool bRet = false;\r
2678         TCHAR szUrl[ATL_URL_MAX_URL_LENGTH];\r
2679         DWORD dwMaxLen = ATL_URL_MAX_URL_LENGTH;\r
2680         if( ! pUrl->CreateUrl(szUrl, &dwMaxLen) )\r
2681                 return false;\r
2683         _ATLTRY\r
2684         {\r
2685                 CA2CT hdr(auth_header);\r
2686                 CAtlNavigateData navigate_data(m_CurrentRequestData);\r
2687                 // append authorization header to extra headers\r
2688                 CString strHeaders = navigate_data.GetExtraHeaders();\r
2689                 strHeaders += hdr;\r
2690                 navigate_data.SetExtraHeaders(strHeaders);\r
2691                 navigate_data.RemoveFlags(ATL_HTTP_FLAG_PROCESS_RESULT);\r
2693                 bRet = m_pSocket->Navigate( szUrl, &navigate_data);\r
2694         }\r
2695         _ATLCATCHALL()\r
2696         {\r
2697                 bRet = false;\r
2698         }\r
2699         if (bRet)\r
2700                 *pszBuffer = (LPSTR)m_pSocket->GetResponse();\r
2701         return bRet;\r
2704 /////////////////////////////////////////////////////////////////////////////////\r
2705 //\r
2706 // CBasicAuthObject\r
2707 // BASIC Security Authorization functions \r
2708 //\r
2709 /////////////////////////////////////////////////////////////////////////////////\r
2710 inline bool CBasicAuthObject::DoBasicAuthenticate() throw()\r
2712         bool bRet = false;\r
2713         ATLASSUME(m_pClient);\r
2714         ATLASSUME(m_pAuthInfo);\r
2715         // Create an authentication string\r
2716         CTempBuffer<TCHAR, (_ATL_MAX_AUTH_BUFF*2)+2> auth_string;\r
2717         CAuthInfoBuffType buffUID;\r
2718         CAuthInfoBuffType buffPWD;\r
2720         DWORD dwUID=0,dwPWD=0;\r
2721         if (!_AtlGetAuthInfoHelper(m_pAuthInfo, &IAuthInfo::GetPassword, buffPWD, &dwPWD) ||\r
2722                 !_AtlGetAuthInfoHelper(m_pAuthInfo, &IAuthInfo::GetUsername, buffUID, &dwUID))\r
2723                 return false;\r
2725         _ATLTRY\r
2726         {\r
2727                 if (!auth_string.Allocate((_ATL_MAX_AUTH_BUFF*2)+2))\r
2728                         return false;\r
2730                 Checked::tcscpy_s(auth_string, _ATL_MAX_AUTH_BUFF, buffUID);\r
2731                 Checked::tcscat_s(auth_string, _ATL_MAX_AUTH_BUFF, _T(":"));\r
2732                 Checked::tcscat_s(auth_string, _ATL_MAX_AUTH_BUFF, buffPWD);\r
2734                 // Base64 encode the auth string\r
2735                 char *auth_string_enc = NULL;\r
2736                 CTempBuffer<char, 512> auth_string_buff;\r
2737                 CT2A auth_string_a(auth_string);\r
2739                 int nLen = Base64EncodeGetRequiredLength((int)strlen((LPSTR)auth_string_a));\r
2740                 auth_string_buff.Allocate(nLen+1);\r
2741                 if (!((char*)auth_string_buff))\r
2742                         return false;\r
2744                 auth_string_enc = (char*)auth_string_buff;\r
2745                 if (!Base64Encode((const BYTE*)(LPSTR)auth_string_a, (int)strlen((LPSTR)auth_string_a),\r
2746                                                   auth_string_enc, &nLen, ATL_BASE64_FLAG_NOCRLF))\r
2747                         return false;\r
2748                 auth_string_buff[nLen]=0;\r
2750                 // Format the Authentication header\r
2751                 int nLenFmt = (m_bProxy ? (int)strlen(m_pszFmtProxy) : (int)strlen(m_pszFmtWWW)) + 2;\r
2752                 nLen += nLenFmt;\r
2753                 ++nLen; // Space for '\0'\r
2754                 \r
2755                 CTempBuffer<char, 512> auth_header_buff;\r
2756                 ATLTRY(auth_header_buff.Allocate(nLen));\r
2757                 if (!((char*)auth_header_buff))\r
2758                         return false;\r
2760                 char *auth_header = (char*)auth_header_buff;\r
2761                 Checked::strcpy_s(auth_header, nLen, m_bProxy ? m_pszFmtProxy : m_pszFmtWWW);\r
2762                 Checked::strcat_s(auth_header, nLen, auth_string_enc);\r
2763                 Checked::strcat_s(auth_header, nLen, "\r\n");\r
2765                 // Resend the request with the authorization information\r
2766                 LPCURL pUrl = m_pClient->GetCurrentUrl();\r
2767                 TCHAR szUrl[ATL_URL_MAX_URL_LENGTH];\r
2768                 DWORD dwMaxLen = ATL_URL_MAX_URL_LENGTH;\r
2769                 pUrl->CreateUrl(szUrl, &dwMaxLen);\r
2771                 // reset the connection if required\r
2772                 m_pClient->ResetConnection();\r
2774                 CA2T hdr(auth_header);\r
2775                 CAtlNavigateData navigate_data(*(const_cast<const ATL_NAVIGATE_DATA*>(m_pClient->GetCurrentNavdata())));\r
2776                 // append authorization header to extra headers\r
2777                 CString strHeaders = navigate_data.GetExtraHeaders();\r
2778                 strHeaders += hdr;\r
2779                 navigate_data.SetExtraHeaders(strHeaders);\r
2780                 navigate_data.RemoveFlags(ATL_HTTP_FLAG_PROCESS_RESULT);\r
2781                 bRet = m_pClient->Navigate( szUrl,\r
2782                                                                         &navigate_data);\r
2783         }\r
2784         _ATLCATCHALL()\r
2785         {\r
2786                 bRet = false;\r
2787         }\r
2789         if (bRet)\r
2790         {\r
2791                 // Request was successfully sent. Process the result.\r
2792                 if (m_pClient->GetStatus() == 401 ||\r
2793                         m_pClient->GetStatus() == 407)\r
2794                 {\r
2795                         // Authorization with this protocol failed.\r
2796                         // don't try it again.\r
2797                         m_pClient->AuthProtocolFailed(_T("basic"));\r
2798                 }\r
2799                 bRet = m_pClient->ProcessStatus(m_pClient->GetFlags());\r
2800         }\r
2801         return bRet;\r
2804 inline CBasicAuthObject::CBasicAuthObject() throw()\r
2806         m_pClient = NULL;\r
2807         m_pAuthInfo = NULL;\r
2808         m_szRealm[0] = 0;\r
2809         m_bProxy = false;\r
2812 inline CBasicAuthObject::CBasicAuthObject(IAuthInfo *pAuthInfo) throw()\r
2814         m_pAuthInfo = pAuthInfo;\r
2815         m_pClient = NULL;\r
2818 inline void CBasicAuthObject::SetAuthInfo(IAuthInfo *pAuthInfo) throw()\r
2820         m_pAuthInfo = pAuthInfo;\r
2823 // Called by the CAtlHttpClient class to \r
2824 // authenticate a user.\r
2825 inline bool CBasicAuthObject::Authenticate(LPCTSTR szAuthTypes, bool bProxy) throw()\r
2827         if (lstrlen(szAuthTypes) > ATL_AUTH_HDR_SIZE)\r
2828                 return false;\r
2830         m_bProxy = bProxy;\r
2832         if (!CrackRealm(szAuthTypes))\r
2833                 return false;\r
2834         return DoBasicAuthenticate();\r
2837 inline LPCTSTR CBasicAuthObject::GetRealm() throw()\r
2839         return const_cast<LPCTSTR>(m_szRealm);\r
2842 // Called by the CAtlHttpClient class to initialize\r
2843 // this authentication object.\r
2844 inline void CBasicAuthObject::Init(CAtlHttpClient *pSocket, IAuthInfo *pAuthInfo) throw()\r
2846         ATLASSERT(pSocket);\r
2847         m_pClient = pSocket;\r
2848         if (pAuthInfo)\r
2849                 SetAuthInfo(pAuthInfo);\r
2852 inline bool CBasicAuthObject::CrackRealm(LPCTSTR szHeader) throw()\r
2854         // szHeader is pointing at the\r
2855         // "basic" in the header\r
2856         // see if realm is available\r
2857         const TCHAR *pStart = szHeader;\r
2859         // skip "basic"\r
2860         pStart += 5;\r
2862         // skip space\r
2863         while (*pStart && _AtlIsHttpSpace(*pStart))\r
2864                 pStart++;\r
2866         // are we pointing at 'realm'?\r
2867         if ((*pStart == 'r' || *pStart == 'R') &&\r
2868                 (*(pStart+1) == 'e' || *(pStart+1) == 'E') &&\r
2869                 (*(pStart+2) == 'a' || *(pStart+2) == 'A') &&\r
2870                 (*(pStart+3) == 'l' || *(pStart+3) == 'L') &&\r
2871                 (*(pStart+4) == 'm' || *(pStart+4) == 'M'))\r
2872         {\r
2873                 // skip 'realm'\r
2874                 pStart += 5;\r
2876                 // skip space\r
2877                 while (*pStart && _AtlIsHttpSpace(*pStart))\r
2878                         pStart++;\r
2880                 // skip '='\r
2881                 if (*pStart && *pStart == _T('='))\r
2882                         pStart++;\r
2883                 else\r
2884                         return false; // invalid realm\r
2886                 // skip space\r
2887                 while (*pStart && _AtlIsHttpSpace(*pStart))\r
2888                         pStart++;\r
2890                 // skip quotes if they are there\r
2891                 if (*pStart == '\"')\r
2892                         pStart++;\r
2894                 const TCHAR *pEnd = pStart;\r
2895                 while (*pEnd && *pEnd != '\"')\r
2896                 {\r
2897                         if (*pEnd == '\\' && *(pEnd + 1)) // escaped character, skip it\r
2898                                 pEnd += 2;\r
2899                         else\r
2900                            pEnd++;\r
2901                 }\r
2903                 if (*pEnd == '\"' && *(pEnd+1) != '\0')\r
2904                         return false; //trailing junk after the quoted realm\r
2906                 if (*pEnd=='\0' || *pEnd =='\"')\r
2907                 {\r
2908                         int nLen = (int)(pEnd-pStart);\r
2909                         if (nLen < MAX_REALM_LEN)\r
2910                         {\r
2911                                 Checked::tcsncpy_s(m_szRealm, _countof(m_szRealm), pStart, nLen);\r
2912                                 m_szRealm[nLen]=0;\r
2913                                 if (!AtlUnescapeUrl(m_szRealm, m_szRealm, NULL, MAX_REALM_LEN))\r
2914                                         return false; // error unescaping the string\r
2915                         }\r
2916                         else\r
2917                                 return false;\r
2918                 }\r
2919         }\r
2920         return true;\r
2923 inline CAtlBaseAuthObject::CAtlBaseAuthObject()\r
2925         m_bFailed = false;\r
2929 inline CAtlNavigateData::CAtlNavigateData() throw()\r
2931         dwFlags =   ATL_HTTP_FLAG_AUTO_REDIRECT|\r
2932                                 ATL_HTTP_FLAG_PROCESS_RESULT|\r
2933                                 ATL_HTTP_FLAG_SEND_BLOCKS;\r
2934         szExtraHeaders = NULL;\r
2935         szMethod = ATL_HTTP_METHOD_GET;\r
2936         nPort = ATL_URL_DEFAULT_HTTP_PORT;\r
2937         pData = NULL;\r
2938         dwDataLen = 0;\r
2939         szDataType = NULL;\r
2940         dwTimeout = ATL_SOCK_TIMEOUT;\r
2941         dwSendBlockSize = ATL_HTTP_DEFAULT_BLOCK_SIZE;\r
2942         dwReadBlockSize = ATL_HTTP_DEFAULT_BLOCK_SIZE;\r
2943         pfnChunkCallback = NULL;\r
2944         pfnSendStatusCallback = NULL;\r
2945         pfnReadStatusCallback = NULL;\r
2946         m_lParamSend = 0;\r
2947         m_lParamRead = 0;\r
2950 inline CAtlNavigateData::CAtlNavigateData(const CAtlNavigateData &rhs)\r
2952         this->operator=(rhs);\r
2955 inline CAtlNavigateData::CAtlNavigateData(const ATL_NAVIGATE_DATA &rhs)\r
2957         this->operator=(rhs);\r
2960 inline CAtlNavigateData& CAtlNavigateData::operator=(const CAtlNavigateData &rhs)\r
2962         return this->operator=(static_cast<const ATL_NAVIGATE_DATA&>(rhs));\r
2965 inline CAtlNavigateData& CAtlNavigateData::operator=(const ATL_NAVIGATE_DATA &rhs)\r
2967         dwFlags = rhs.dwFlags;\r
2968         szExtraHeaders = rhs.szExtraHeaders;\r
2969         szMethod = rhs.szMethod;\r
2970         nPort = rhs.nPort;\r
2971         pData = rhs.pData;\r
2972         dwDataLen = rhs.dwDataLen;\r
2973         szDataType = rhs.szDataType;\r
2974         dwTimeout = rhs.dwTimeout;\r
2975         dwSendBlockSize = rhs.dwSendBlockSize;\r
2976         dwReadBlockSize = rhs.dwReadBlockSize;\r
2977         pfnChunkCallback = rhs.pfnChunkCallback;\r
2978         pfnSendStatusCallback = rhs.pfnSendStatusCallback;\r
2979         pfnReadStatusCallback = rhs.pfnReadStatusCallback;\r
2980         m_lParamSend = rhs.m_lParamSend;\r
2981         m_lParamRead = rhs.m_lParamRead;\r
2982         return *this;\r
2985 inline DWORD CAtlNavigateData::SetFlags(DWORD dwNewFlags) throw()\r
2987         // check for mutually exclusive flags\r
2988         if ((dwNewFlags & ATL_HTTP_FLAG_SEND_CALLBACK) &&\r
2989                 (dwNewFlags & ATL_HTTP_FLAG_SEND_BLOCKS))\r
2990         {\r
2991                 ATLASSERT(0);\r
2992                 return ATL_HTTP_FLAG_INVALID_FLAGS;\r
2993         }\r
2995         DWORD dwOldFlags = dwFlags;\r
2996         dwFlags = dwNewFlags;\r
2997         return dwOldFlags;\r
3000 inline DWORD CAtlNavigateData::GetFlags() throw()\r
3002         return dwFlags;\r
3005 inline DWORD CAtlNavigateData::AddFlags(DWORD dwFlagsToAdd) throw()\r
3007                 // check for mutually exclusive flags\r
3008         if (\r
3009                 ((dwFlagsToAdd & ATL_HTTP_FLAG_SEND_CALLBACK) &&\r
3010                  (dwFlags & ATL_HTTP_FLAG_SEND_BLOCKS)) ||\r
3011                 ((dwFlagsToAdd & ATL_HTTP_FLAG_SEND_BLOCKS) &&\r
3012                  (dwFlags & ATL_HTTP_FLAG_SEND_CALLBACK))\r
3013            )\r
3014         {\r
3015                 ATLASSERT(0);\r
3016                 return ATL_HTTP_FLAG_INVALID_FLAGS;\r
3017         }\r
3019         DWORD dwOldFlags = dwFlags;\r
3020         dwFlags |= dwFlagsToAdd;\r
3021         return dwOldFlags;\r
3024 inline DWORD CAtlNavigateData::RemoveFlags(DWORD dwFlagsToRemove) throw()\r
3026         DWORD dwOldFlags = dwFlags;\r
3027         dwFlags &= ~dwFlagsToRemove;\r
3028         return dwOldFlags;\r
3031 inline LPCTSTR CAtlNavigateData::SetExtraHeaders(LPCTSTR szNewHeaders) throw()\r
3033         LPCTSTR szold = szExtraHeaders;\r
3034         szExtraHeaders = szNewHeaders;\r
3035         return szold;\r
3038 inline LPCTSTR CAtlNavigateData::GetExtraHeaders() throw()\r
3040         return szExtraHeaders;  \r
3042 inline LPCTSTR CAtlNavigateData::SetMethod(LPCTSTR szNewMethod) throw()\r
3044         LPCTSTR szold = szMethod;\r
3045         szMethod = szNewMethod;\r
3046         return szold;\r
3048 inline LPCTSTR CAtlNavigateData::GetMethod() throw()\r
3050         return szMethod;\r
3052 inline short CAtlNavigateData::SetPort(short newPort) throw()\r
3054         short oldport = nPort;\r
3055         nPort = newPort;\r
3056         return oldport;\r
3058 inline short CAtlNavigateData::GetPort() throw()\r
3060         return nPort;\r
3062 inline void CAtlNavigateData::SetPostData(BYTE *pd, DWORD len, LPCTSTR type) throw()\r
3064         pData = pd;\r
3065         dwDataLen = len;\r
3066         szDataType = type;\r
3069 inline DWORD CAtlNavigateData::SetSocketTimeout(DWORD dwNewTimeout) throw()\r
3071         DWORD dwold = dwTimeout;\r
3072         dwTimeout = dwNewTimeout;\r
3073         return dwold;\r
3075 inline DWORD CAtlNavigateData::GetSocketTimeout() throw()\r
3077         return dwTimeout;\r
3079 inline DWORD CAtlNavigateData::SetSendBlockSize(DWORD dwNewBlockSize) throw()\r
3081         DWORD dwold = dwSendBlockSize;\r
3082         dwSendBlockSize = dwNewBlockSize;\r
3083         return dwold;\r
3085 inline DWORD CAtlNavigateData::GetSendBlockSize() throw()\r
3087         return dwSendBlockSize;\r
3090 inline DWORD CAtlNavigateData::SetReadBlockSize(DWORD dwNewBlockSize) throw()\r
3092         DWORD dwold = dwReadBlockSize;\r
3093         dwReadBlockSize = dwNewBlockSize;\r
3094         return dwold;\r
3097 inline DWORD CAtlNavigateData::GetReadBlockSize() throw()\r
3099         return dwReadBlockSize;\r
3102 inline PFNATLCHUNKEDCB CAtlNavigateData::SetChunkCallback(PFNATLCHUNKEDCB pfn, DWORD_PTR dwParam) throw()\r
3104         PFNATLCHUNKEDCB pold = pfnChunkCallback;\r
3105         pfnChunkCallback = pfn;\r
3106         m_lParamChunkCB = dwParam;\r
3107         return pold;\r
3109 inline PFNATLCHUNKEDCB CAtlNavigateData::GetChunkCallback() throw()\r
3111         return pfnChunkCallback;\r
3114 inline PFNATLSTATUSCALLBACK CAtlNavigateData::SetSendStatusCallback(PFNATLSTATUSCALLBACK pfn, DWORD_PTR dwData) throw()\r
3116         PFNATLSTATUSCALLBACK pold = pfnSendStatusCallback;\r
3117         pfnSendStatusCallback = pfn;\r
3118         m_lParamSend = dwData;\r
3119         return pold;\r
3122 inline PFNATLSTATUSCALLBACK CAtlNavigateData::GetSendStatusCallback() throw()\r
3124         return pfnSendStatusCallback;\r
3127 inline PFNATLSTATUSCALLBACK CAtlNavigateData::SetReadStatusCallback(PFNATLSTATUSCALLBACK pfn, DWORD_PTR dwData) throw()\r
3129         PFNATLSTATUSCALLBACK pOld = pfnReadStatusCallback;\r
3130         pfnReadStatusCallback = pfn;\r
3131         m_lParamRead = dwData;\r
3132         return pOld;\r
3135 inline PFNATLSTATUSCALLBACK CAtlNavigateData::GetReadStatusCallback() throw()\r
3137         return pfnReadStatusCallback;\r
3140 } // namespace ATL\r
3142 #pragma warning(pop)\r
3144 #endif // __ATLHTTP_INL__\r