cbSize
, dwFlags
, etc. Or, to get a string, first find out its size, prepare a buffer and then only get the string itself. Then we will talk about the function ::HttpQueryInfo()
and the use of the idiom "traits" to simplify working with it. // Retrieving Headers Using a Constant BOOL SampleCodeOne(HINTERNET hHttp) { LPVOID lpOutBuffer=NULL; DWORD dwSize = 0; retry: // This call will fail on the first pass, because // no buffer is allocated. if(!HttpQueryInfo(hHttp,HTTP_QUERY_RAW_HEADERS_CRLF, (LPVOID)lpOutBuffer,&dwSize,NULL)) { if (GetLastError()==ERROR_HTTP_HEADER_NOT_FOUND) { // Code to handle the case where the header isn't available. return TRUE; } else { // Check for an insufficient buffer. if (GetLastError()==ERROR_INSUFFICIENT_BUFFER) { // Allocate the necessary buffer. lpOutBuffer = new char[dwSize]; // Retry the call. goto retry; } else { // Error handling code. delete [] lpOutBuffer; return FALSE; } } } delete [] lpOutBuffer; return TRUE; }
delete []
can also be called for a null pointer). const int code = get_header<HTTP_QUERY_STATUS_CODE>(hRequest) ; const int responseBodySize = get_header<HTTP_QUERY_CONTENT_LENGTH>(hRequest) ; const CString allHeaders = get_header<HTTP_QUERY_RAW_HEADERS_CRLF>(hRequest) ;
get_header
should depend on the specified header. template <DWORD I> TypeDependentOfI get_header(HINTERNET aRequest) { return Magic(aRequest, I) ; }
using ATL::CString ; template <DWORD I> struct header_traits ; template <> struct header_traits<HTTP_QUERY_STATUS_CODE> { typedef DWORD result_type ; } ; template <> struct header_traits<HTTP_QUERY_CONTENT_LENGTH> { typedef DWORD result_type ; } ; template <> struct header_traits<HTTP_QUERY_RAW_HEADERS_CRLF> { typedef CString result_type ; } ;
struct string_getter { typedef CString result_type ; static type get(HINTERNET aRequest, DWORD aValueCode) { DWORD len = 0 ; const BOOL r1 = ::HttpQueryInfo(aRequest, aValueCode, 0, IN OUT &len, 0) ; if (len > 0) { CString res ; const DWORD r2 = ::HttpQueryInfo(aRequest, aValueCode, OUT res.GetBufferSetLength(len + 1), IN OUT &len, 0) ; if (r2 != 0) return res ; } return CString() ; } } ; struct num_getter { typedef DWORD result_type ; static type get(HINTERNET aRequest, DWORD aValueCode) { static const int KMaxLen = 16 ; TCHAR buf[KMaxLen + 1] ; ZeroSizeOf(buf) ; DWORD len = KMaxLen ; if (::HttpQueryInfo(aRequest, aValueCode, OUT buf, IN OUT &len, 0)) { return (DWORD)_tcstoul(buf) ; } return 0 ; } } ;
template <> struct header_traits<HTTP_QUERY_STATUS_CODE> { typedef num_getter getter ; } ; template <> struct header_traits<HTTP_QUERY_CONTENT_LENGTH> { typedef num_getter getter ; } ; template <> struct header_traits<HTTP_QUERY_RAW_HEADERS_CRLF> { typedef string_getter getter ; } ;
#define DECLARE_STRING_HEADER_GETTER(code) \ template <> struct header_traits<code> \ { typedef string_getter getter ; } ; #define DECLARE_NUM_HEADER_GETTER(code) \ template <> struct header_traits<code> \ { typedef num_getter getter ; } ; DECLARE_NUM_HEADER_GETTER(HTTP_QUERY_STATUS_CODE) DECLARE_NUM_HEADER_GETTER(HTTP_QUERY_CONTENT_LENGTH) DECLARE_STRING_HEADER_GETTER(HTTP_QUERY_RAW_HEADERS_CRLF) DECLARE_STRING_HEADER_GETTER(HTTP_QUERY_CONTENT_DISPOSITION) // ... #undef DECLARE_NUM_HEADER_GETTER #undef DECLARE_STRING_HEADER_GETTER
get_header()
takes the form: template <DWORD I> typename header_traits<I>::getter::type get_header(HINTERNET aRequest) { return typename header_traits<I>::getter::get(aRequest, I) ; }
Source: https://habr.com/ru/post/89922/
All Articles