Exemplo n.º 1
0
static int certificate_check(winhttp_stream *s, int valid)
{
	int error;
	winhttp_subtransport *t = OWNING_SUBTRANSPORT(s);
	PCERT_CONTEXT cert_ctx;
	DWORD cert_ctx_size = sizeof(cert_ctx);
	git_cert_x509 cert;

	/* If there is no override, we should fail if WinHTTP doesn't think it's fine */
	if (t->owner->certificate_check_cb == NULL && !valid)
		return GIT_ECERTIFICATE;

	if (t->owner->certificate_check_cb == NULL || !t->connection_data.use_ssl)
		return 0;

	if (!WinHttpQueryOption(s->request, WINHTTP_OPTION_SERVER_CERT_CONTEXT, &cert_ctx, &cert_ctx_size)) {
		giterr_set(GITERR_OS, "failed to get server certificate");
		return -1;
	}

	giterr_clear();
	cert.cert_type = GIT_CERT_X509;
	cert.data = cert_ctx->pbCertEncoded;
	cert.len = cert_ctx->cbCertEncoded;
	error = t->owner->certificate_check_cb((git_cert *) &cert, valid, t->connection_data.host, t->owner->cred_acquire_payload);
	CertFreeCertificateContext(cert_ctx);

	if (error < 0 && !giterr_last())
		giterr_set(GITERR_NET, "user cancelled certificate check");

	return error;
}
Exemplo n.º 2
0
void web_file::OnHeadersReady( HINTERNET hRequest )
{
	WCHAR buf[2048];
	DWORD len = sizeof(buf);
	if (WinHttpQueryOption(m_hRequest, WINHTTP_OPTION_URL, buf, &len))
	{
		m_realUrl = buf;
	}
}
Exemplo n.º 3
0
static void CALLBACK check_notification( HINTERNET handle, DWORD_PTR context, DWORD status, LPVOID buffer, DWORD buflen )
{
    BOOL status_ok, function_ok;
    struct info *info = (struct info *)context;
    unsigned int i = info->index;

    if (status == WINHTTP_CALLBACK_STATUS_HANDLE_CREATED)
    {
        DWORD size = sizeof(struct info *);
        WinHttpQueryOption( handle, WINHTTP_OPTION_CONTEXT_VALUE, &info, &size );
    }
    ok(i < info->count, "unexpected notification 0x%08x\n", status);
    if (i >= info->count) return;

    status_ok   = (info->test[i].status == status);
    function_ok = (info->test[i].function == info->function);
    if (!info->test[i].ignore && !info->test[i].todo)
    {
        ok(status_ok, "%u: expected status 0x%08x got 0x%08x\n", info->line, info->test[i].status, status);
        ok(function_ok, "%u: expected function %u got %u\n", info->line, info->test[i].function, info->function);
    }
    else if (!info->test[i].ignore)
    {
        todo_wine ok(status_ok, "%u: expected status 0x%08x got 0x%08x\n", info->line, info->test[i].status, status);
        if (status_ok)
        {
            todo_wine ok(function_ok, "%u: expected function %u got %u\n", info->line, info->test[i].function, info->function);
        }
    }
    if (status_ok && function_ok) info->index++;
    if (proxy_active())
    {
        while (info->test[info->index].skipped_for_proxy)
            info->index++;
    }

    if (status & (WINHTTP_CALLBACK_FLAG_ALL_COMPLETIONS | WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING))
    {
        SetEvent( info->wait );
    }
}
Exemplo n.º 4
0
// handle WinHTTP callbacks (which can be in a worker thread context)
VOID CALLBACK WinHttpIO::asynccallback(HINTERNET hInternet, DWORD_PTR dwContext,
                                       DWORD dwInternetStatus,
                                       LPVOID lpvStatusInformation,
                                       DWORD dwStatusInformationLength)
{
    WinHttpContext* httpctx = (WinHttpContext*)dwContext;
    WinHttpIO* httpio = (WinHttpIO*)httpctx->httpio;

    if (dwInternetStatus == WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING)
    {
        LOG_verbose << "Closing request";
        assert(!httpctx->req);

        if (httpctx->gzip)
        {
            inflateEnd(&httpctx->z);
        }
        
        delete httpctx;
        return;
    }

    httpio->lock();

    HttpReq* req = httpctx->req;

    // request cancellations that occured after asynccallback() was entered are caught here
    if (!req)
    {
        LOG_verbose << "Request cancelled";
        httpio->unlock();
        return;
    }

    switch (dwInternetStatus)
    {
        case WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE:
        {
            DWORD size = *(DWORD*)lpvStatusInformation;

            if (!size)
            {
                if (req->binary)
                {
                    LOG_debug << "[received " << (req->buf ? req->buflen : req->in.size()) << " bytes of raw data]";
                }
                else
                {
                    if(req->in.size() < 2048)
                    {
                        LOG_debug << "Received: " << req->in.c_str();
                    }
                    else
                    {
                        LOG_debug << "Received: " << req->in.substr(0,2048).c_str();
                    }
                }

                LOG_debug << "Request finished with HTTP status: " << req->httpstatus;
                req->status = (req->httpstatus == 200
                            && (req->contentlength < 0
                             || req->contentlength == (req->buf ? req->bufpos : (int)req->in.size())))
                             ? REQ_SUCCESS : REQ_FAILURE;

                if (req->status == REQ_SUCCESS)
                {
                    httpio->lastdata = Waiter::ds;
                }
                httpio->success = true;
            }
            else
            {
                LOG_verbose << "Data available. Remaining: " << size << " bytes";

                char* ptr;

                if (httpctx->gzip)
                {                    
                    m_off_t zprevsize = httpctx->zin.size();
                    httpctx->zin.resize(zprevsize + size);
                    ptr = (char*)httpctx->zin.data() + zprevsize;
                }
                else
                {                    
                    ptr = (char*)req->reserveput((unsigned*)&size);
                    req->bufpos += size;
                }

                if (!WinHttpReadData(hInternet, ptr, size, NULL))
                {
                    LOG_err << "Unable to get more data. Code: " << GetLastError();
                    httpio->cancel(req);
                }
            }

            httpio->httpevent();
            break;
        }

        case WINHTTP_CALLBACK_STATUS_READ_COMPLETE:
            LOG_verbose << "Read complete";

            if (dwStatusInformationLength)
            {
                LOG_verbose << dwStatusInformationLength << " bytes received";
                if (req->httpio)
                {
                    req->httpio->lastdata = Waiter::ds;
                }
            
                if (httpctx->gzip)
                {                    
                    httpctx->z.next_in = (Bytef*)lpvStatusInformation;
                    httpctx->z.avail_in = dwStatusInformationLength;

                    req->bufpos += httpctx->z.avail_out;
                    int t = inflate(&httpctx->z, Z_SYNC_FLUSH);
                    req->bufpos -= httpctx->z.avail_out;

                    if ((char*)lpvStatusInformation + dwStatusInformationLength ==
                             httpctx->zin.data() + httpctx->zin.size())
                    {
                        httpctx->zin.clear();
                    }

                    if (t != Z_OK && (t != Z_STREAM_END || httpctx->z.avail_out))
                    {
                        LOG_err << "GZIP error";
                        httpio->cancel(req);
                    }
                }

                if (!WinHttpQueryDataAvailable(httpctx->hRequest, NULL))
                {
                    LOG_err << "Error on WinHttpQueryDataAvailable. Code: " << GetLastError();
                    httpio->cancel(req);
                    httpio->httpevent();
                }
            }
            break;

        case WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE:
        {
            DWORD statusCode;
            DWORD statusCodeSize = sizeof(statusCode);

            if (!WinHttpQueryHeaders(httpctx->hRequest,
                                     WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER,
                                     WINHTTP_HEADER_NAME_BY_INDEX,
                                     &statusCode,
                                     &statusCodeSize,
                                     WINHTTP_NO_HEADER_INDEX))
            {
                LOG_err << "Error getting headers. Code: " << GetLastError();
                httpio->cancel(req);
                httpio->httpevent();
            }
            else
            {
                LOG_verbose << "Headers available";

                req->httpstatus = statusCode;

                if (req->httpio)
                {
                    req->httpio->lastdata = Waiter::ds;
                }

                if (!req->buf)
                {
                    // obtain original content length - always present if gzip is in use
                    DWORD contentLength;
                    DWORD contentLengthSize = sizeof(contentLength);

                    if (WinHttpQueryHeaders(httpctx->hRequest,
                                            WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_NUMBER,
                                            L"Original-Content-Length",
                                            &contentLength,
                                            &contentLengthSize,
                                            WINHTTP_NO_HEADER_INDEX))
                    {
                        LOG_verbose << "Content-Length: " << contentLength;
                        req->setcontentlength(contentLength);

                        // check for gzip content encoding
                        WCHAR contentEncoding[16];
                        DWORD contentEncodingSize = sizeof(contentEncoding);

                        httpctx->gzip = WinHttpQueryHeaders(httpctx->hRequest,
                                                WINHTTP_QUERY_CONTENT_ENCODING,
                                                WINHTTP_HEADER_NAME_BY_INDEX,
                                                &contentEncoding,
                                                &contentEncodingSize,
                                                WINHTTP_NO_HEADER_INDEX)
                                    && !wcscmp(contentEncoding, L"gzip");

                        if (httpctx->gzip)
                        {
                            LOG_verbose << "Using GZIP";

                            httpctx->z.zalloc = Z_NULL;
                            httpctx->z.zfree = Z_NULL;
                            httpctx->z.opaque = Z_NULL;
                            httpctx->z.avail_in = 0;
                            httpctx->z.next_in = Z_NULL;

                            inflateInit2(&httpctx->z, MAX_WBITS+16);

                            req->in.resize(contentLength);
                            httpctx->z.avail_out = contentLength;
                            httpctx->z.next_out = (unsigned char*)req->in.data();
                        }
                        else
                        {
                            LOG_verbose << "Not using GZIP";
                        }
                    }
                    else
                    {
                        LOG_verbose << "Content-Length not available";
                    }
                }

                if (!WinHttpQueryDataAvailable(httpctx->hRequest, NULL))
                {
                    LOG_err << "Unable to query data. Code: " << GetLastError();

                    httpio->cancel(req);
                    httpio->httpevent();
                }
                else if (httpio->waiter && httpio->noinetds)
                {
                    httpio->inetstatus(true);
                }
            }

            break;
        }

        case WINHTTP_CALLBACK_STATUS_REQUEST_ERROR:
        {
            DWORD e = GetLastError();

            LOG_err << "Request error. Code: " << e;

            if (httpio->waiter && e != ERROR_WINHTTP_TIMEOUT)
            {
                httpio->inetstatus(false);
            }
        }
        // fall through
        case WINHTTP_CALLBACK_STATUS_SECURE_FAILURE:
            if (dwInternetStatus == WINHTTP_CALLBACK_STATUS_SECURE_FAILURE)
            {
                LOG_err << "Security check failed. Code: " << (*(DWORD*)lpvStatusInformation);
            }

            httpio->cancel(req);
            httpio->httpevent();
            break;

        case WINHTTP_CALLBACK_STATUS_SENDING_REQUEST:
        {
            if(MegaClient::disablepkp)
            {
                break;
            }

            PCCERT_CONTEXT cert;
            DWORD len = sizeof cert;

            if (WinHttpQueryOption(httpctx->hRequest, WINHTTP_OPTION_SERVER_CERT_CONTEXT, &cert, &len))
            {
                CRYPT_BIT_BLOB* pkey = &cert->pCertInfo->SubjectPublicKeyInfo.PublicKey;

                // this is an SSL connection: verify public key to prevent MITM attacks
                if (pkey->cbData != 270
                 || (memcmp(pkey->pbData, "\x30\x82\x01\x0a\x02\x82\x01\x01\x00" APISSLMODULUS1
                                          "\x02" APISSLEXPONENTSIZE APISSLEXPONENT, 270)
                  && memcmp(pkey->pbData, "\x30\x82\x01\x0a\x02\x82\x01\x01\x00" APISSLMODULUS2
                                          "\x02" APISSLEXPONENTSIZE APISSLEXPONENT, 270)))
                {
                    LOG_err << "Certificate error. Possible MITM attack!!";
                    CertFreeCertificateContext(cert);
                    httpio->cancel(req);
                    httpio->httpevent();
                    break;
                }

                CertFreeCertificateContext(cert);
            }

            break;
        }

        case WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE:
        case WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE:
            if (httpctx->postpos < httpctx->postlen)
            {
                LOG_verbose << "Chunk written";
                unsigned pos = httpctx->postpos;
                unsigned t = httpctx->postlen - pos;

                if (t > HTTP_POST_CHUNK_SIZE)
                {
                    t = HTTP_POST_CHUNK_SIZE;
                }

                httpctx->postpos += t;

                if (!WinHttpWriteData(httpctx->hRequest, (LPVOID)(httpctx->postdata + pos), t, NULL))
                {
                    LOG_err << "Error writting data. Code: " << GetLastError();
                    req->httpio->cancel(req);
                }

                httpio->httpevent();
            }
            else
            {
                LOG_verbose << "Request written";
                if (!WinHttpReceiveResponse(httpctx->hRequest, NULL))
                {
                    LOG_err << "Error receiving response. Code: " << GetLastError();
                    httpio->cancel(req);
                    httpio->httpevent();
                }

                httpctx->postdata = NULL;
            }
    }

    httpio->unlock();
}
/*!
 * @brief Wrapper around WinHTTP-specific request response validation.
 * @param hReq HTTP request handle.
 * @param ctx The HTTP transport context.
 * @return An indication of the result of getting a response.
 */
static DWORD validate_response_winhttp(HANDLE hReq, HttpTransportContext* ctx)
{
	DWORD statusCode;
	DWORD statusCodeSize = sizeof(statusCode);
	vdprintf("[PACKET RECEIVE WINHTTP] Getting the result code...");
	if (WinHttpQueryHeaders(hReq, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, WINHTTP_HEADER_NAME_BY_INDEX, &statusCode, &statusCodeSize, WINHTTP_NO_HEADER_INDEX))
	{
		vdprintf("[PACKET RECEIVE WINHTTP] Returned status code is %d", statusCode);

		// did the request succeed?
		if (statusCode != 200)
		{
			// There are a few reasons why this could fail, including proxy related stuff.
			// If we fail, we're going to fallback to WinINET and see if that works instead.
			// there could be a number of reasons for failure, but we're only going to try
			// to handle the case where proxy authentication fails. We'll indicate failure and
			// let the switchover happen for us.

			// However, we won't do this in the case where cert hash verification is turned on,
			// because we don't want to expose people to MITM if they've explicitly asked us not
			// to.
			if (ctx->cert_hash == NULL && statusCode == 407)
			{
				return ERROR_WINHTTP_CANNOT_CONNECT;
			}

			// indicate something is up.
			return ERROR_BAD_CONFIGURATION;
		}
	}

	if (ctx->cert_hash != NULL)
	{
		vdprintf("[PACKET RECEIVE WINHTTP] validating certificate hash");
		PCERT_CONTEXT pCertContext = NULL;
		DWORD dwCertContextSize = sizeof(pCertContext);

		if (!WinHttpQueryOption(hReq, WINHTTP_OPTION_SERVER_CERT_CONTEXT, &pCertContext, &dwCertContextSize))
		{
			dprintf("[PACKET RECEIVE WINHTTP] Failed to get the certificate context: %u", GetLastError());
			return ERROR_WINHTTP_SECURE_INVALID_CERT;
		}

		DWORD dwHashSize = 20;
		BYTE hash[20];
		if (!CertGetCertificateContextProperty(pCertContext, CERT_SHA1_HASH_PROP_ID, hash, &dwHashSize))
		{
			dprintf("[PACKET RECEIVE WINHTTP] Failed to get the certificate hash: %u", GetLastError());
			return ERROR_WINHTTP_SECURE_INVALID_CERT;
		}

		if (memcmp(hash, ctx->cert_hash, CERT_HASH_SIZE) != 0)
		{
			dprintf("[SERVER] Server hash set to: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
				hash[0], hash[1], hash[2], hash[3], hash[4], hash[5], hash[6], hash[7], hash[8], hash[9], hash[10],
				hash[11], hash[12], hash[13], hash[14], hash[15], hash[16], hash[17], hash[18], hash[19]);

			dprintf("[PACKET RECEIVE WINHTTP] Certificate hash doesn't match, bailing out");
			return ERROR_WINHTTP_SECURE_INVALID_CERT;
		}
	}

	return ERROR_SUCCESS;
}
Exemplo n.º 6
0
// Read URL server
LPSTR SoffidEssoManager::readURL (HINTERNET hSession, const wchar_t* host, int port,
		LPCWSTR path, BOOL allowUnknownCA, size_t *pSize)
{
	BOOL bResults = FALSE;
	HINTERNET hConnect = NULL, hRequest = NULL;

	DWORD dwDownloaded = -1;
	BYTE *buffer = NULL;

	if (debug)
	{
		log("Connecting to %s:%d...\n", host, port);
	}

	hConnect = WinHttpConnect(hSession, host, port, 0);

	if (hConnect)
	{
		if (debug)
		{
			log("Performing request %s...\n", path);
		}

		hRequest = WinHttpOpenRequest(hConnect, L"GET", path, NULL, WINHTTP_NO_REFERER,
				WINHTTP_DEFAULT_ACCEPT_TYPES, WINHTTP_FLAG_SECURE);
	}

	// Send a request.
	if (hRequest)
	{
		if (debug)
			log("Sending request ...\n");

		WinHttpSetOption(hRequest, WINHTTP_OPTION_CLIENT_CERT_CONTEXT, NULL, 0);

		if (allowUnknownCA)
		{
			DWORD flags = SECURITY_FLAG_IGNORE_UNKNOWN_CA;
			WinHttpSetOption(hRequest, WINHTTP_OPTION_SECURITY_FLAGS, (LPVOID) &flags,
					sizeof flags);
		}

		bResults = WinHttpSendRequest(hRequest, WINHTTP_NO_ADDITIONAL_HEADERS, 0,
				WINHTTP_NO_REQUEST_DATA, 0, 0, 0);
	}

	if (bResults && allowUnknownCA)
	{
		// Agreagar la CA ROOT
		PCERT_CONTEXT context;
		DWORD dwSize = sizeof context;
		BOOL result = WinHttpQueryOption(hRequest, WINHTTP_OPTION_SERVER_CERT_CONTEXT,
				&context, &dwSize);

		if (!result)
		{
			log("Cannot get context\n");
//			notifyError();
		}

		PCCERT_CONTEXT issuerContext = CertFindCertificateInStore(context->hCertStore,
				X509_ASN_ENCODING, 0, CERT_FIND_ISSUER_OF, context, NULL);
		HCERTSTORE systemStore = CertOpenStore((LPCSTR) 13, // CERT_STORE_PROV_SYSTEM_REGISTRY_W
				0, (HCRYPTPROV) NULL, (2 << 16) | // CERT_SYSTEM_STORE_LOCAL_MACHINE
						0x1000, // CERT_STORE_MAXIMUM_ALLOWED
				L"ROOT");
		CertAddCertificateContextToStore(systemStore, issuerContext,
				1 /*CERT_STORE_ADD_NEW*/, NULL);

		CertFreeCertificateContext(issuerContext);
		CertFreeCertificateContext(context);
	}

	// End the request.
	if (bResults)
	{
		if (debug)
			log("Waiting for response....\n");

		bResults = WinHttpReceiveResponse(hRequest, NULL);
	}

	// Keep checking for data until there is nothing left.
	DWORD used = 0;
	if (bResults)
	{
		const DWORD chunk = 4096;
		DWORD allocated = 0;
		do
		{
			if (used + chunk > allocated)
			{
				allocated += chunk;
				buffer = (LPBYTE) realloc(buffer, allocated);
			}

			dwDownloaded = 0;
			if (!WinHttpReadData(hRequest, &buffer[used], chunk, &dwDownloaded))
				dwDownloaded = -1;

			else
				used += dwDownloaded;
		} while (dwDownloaded > 0);

		buffer[used] = '\0';
	}

	DWORD dw = GetLastError();
	if (!bResults && debug)
	{
		if (dw == ERROR_WINHTTP_CANNOT_CONNECT)
			log("Error: Cannot connect\n");
		else if (dw == ERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDED)
			log("Error: Client CERT required\n");
		else if (dw == ERROR_WINHTTP_CONNECTION_ERROR)
			log("Error: Connection error\n");
		else if (dw == ERROR_WINHTTP_INCORRECT_HANDLE_STATE)
			log("Error: ERROR_WINHTTP_INCORRECT_HANDLE_STATE\n");
		else if (dw == ERROR_WINHTTP_INCORRECT_HANDLE_TYPE)
			log("Error: ERROR_WINHTTP_INCORRECT_HANDLE_TYPE\n");
		else if (dw == ERROR_WINHTTP_INTERNAL_ERROR)
			log("Error: ERROR_WINHTTP_INTERNAL_ERROR\n");
		else if (dw == ERROR_WINHTTP_INVALID_URL)
			log("Error: ERROR_WINHTTP_INVALID_URL\n");
		else if (dw == ERROR_WINHTTP_LOGIN_FAILURE)
			log("Error: ERROR_WINHTTP_LOGIN_FAILURE\n");
		else if (dw == ERROR_WINHTTP_NAME_NOT_RESOLVED)
			log("Error: ERROR_WINHTTP_NAME_NOT_RESOLVED\n");
		else if (dw == ERROR_WINHTTP_OPERATION_CANCELLED)
			log("Error: ERROR_WINHTTP_OPERATION_CANCELLED\n");
		else if (dw == ERROR_WINHTTP_RESPONSE_DRAIN_OVERFLOW)
			log("Error: ERROR_WINHTTP_RESPONSE_DRAIN_OVERFLOW\n");
		else if (dw == ERROR_WINHTTP_SECURE_FAILURE)
			log("Error: ERROR_WINHTTP_SECURE_FAILURE\n");
		else if (dw == ERROR_WINHTTP_SHUTDOWN)
			log("Error: ERROR_WINHTTP_SHUTDOWN\n");
		else if (dw == ERROR_WINHTTP_TIMEOUT)
			log("Error: ERROR_WINHTTP_TIMEOUT\n");
		else if (dw == ERROR_WINHTTP_UNRECOGNIZED_SCHEME)
			log("Error: ERROR_WINHTTP_UNRECOGNIZED_SCHEME\n");
		else if (dw == ERROR_NOT_ENOUGH_MEMORY)
			log("Error: ERROR_NOT_ENOUGH_MEMORY\n");
		else if (dw == ERROR_INVALID_PARAMETER)
			log("Error: ERROR_INVALID_PARAMETER\n");
		else if (dw == ERROR_WINHTTP_RESEND_REQUEST)
			log("Error:  ERROR_WINHTTP_RESEND_REQUEST\n");
		else if (dw != ERROR_SUCCESS)
		{
			log("Unkonwn error %d\n", dw);
		}
//		notifyError();
	}

	// Close any open handles.
	if (hRequest)
		WinHttpCloseHandle(hRequest);
	if (hConnect)
		WinHttpCloseHandle(hConnect);
	if (hSession)
		WinHttpCloseHandle(hSession);

	SetLastError(dw);

	if (pSize != NULL)
		*pSize = used;

	return (LPSTR) buffer;
}
Exemplo n.º 7
0
int main(int argc, char *argv[])
{
    DWORD data;
    DWORD dwSize = sizeof(DWORD);

    // Use WinHttpOpen to obtain an HINTERNET handle.
    HINTERNET hSession = WinHttpOpen(
        L"A WinHTTP Example Program/1.0",
        WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
        WINHTTP_NO_PROXY_NAME,
        WINHTTP_NO_PROXY_BYPASS,
        0);
    if (hSession)
    {


        // Use WinHttpQueryOption to retrieve internet options.
        if (WinHttpQueryOption( hSession,
                WINHTTP_OPTION_CONNECT_TIMEOUT,
                &data, &dwSize))
        {
            printf("Connection timeout: %u ms\n\n",data);
        }
        else
        {
            printf( "Error %u in WinHttpQueryOption.\n",
                GetLastError());
        }

        // When finished, release the HINTERNET handle.
        WinHttpCloseHandle(hSession);
    }
    else
    {
        printf("Error %u in WinHttpOpen.\n", GetLastError());
    }

    //DWORD dwSize = 0;
    DWORD dwDownloaded = 0;
    LPSTR pszOutBuffer;
    BOOL  bResults = FALSE;
    //HINTERNET  hSession = NULL;
    HINTERNET  hConnect = NULL;
    HINTERNET  hRequest = NULL;

    // Use WinHttpOpen to obtain a session handle.
    hSession = WinHttpOpen( L"WinHTTP Example/1.0",
        WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
        WINHTTP_NO_PROXY_NAME,
        WINHTTP_NO_PROXY_BYPASS, 0 );

    // Specify an HTTP server.
    if( hSession )
        hConnect = WinHttpConnect( hSession, L"www.microsoft.com",
            INTERNET_DEFAULT_HTTPS_PORT, 0 );

    // Create an HTTP request handle.
    if( hConnect )
        hRequest = WinHttpOpenRequest( hConnect, L"GET", NULL,
            NULL, WINHTTP_NO_REFERER,
            WINHTTP_DEFAULT_ACCEPT_TYPES,
            WINHTTP_FLAG_SECURE );

    // Send a request.
    if( hRequest )
        bResults = WinHttpSendRequest( hRequest,
            WINHTTP_NO_ADDITIONAL_HEADERS, 0,
            WINHTTP_NO_REQUEST_DATA, 0,
            0, 0 );


    // End the request.
    if( bResults )
        bResults = WinHttpReceiveResponse( hRequest, NULL );

    // Keep checking for data until there is nothing left.
    if( bResults )
    {
        do
        {
            // Check for available data.
            dwSize = 0;
            if( !WinHttpQueryDataAvailable( hRequest, &dwSize ) )
                printf( "Error %u in WinHttpQueryDataAvailable.\n",
                    GetLastError( ) );

            // Allocate space for the buffer.
            pszOutBuffer = new char[dwSize+1];
            if( !pszOutBuffer )
            {
                printf( "Out of memory\n" );
                dwSize=0;
            }
            else
            {
                // Read the data.
                ZeroMemory( pszOutBuffer, dwSize+1 );

                if( !WinHttpReadData( hRequest, (LPVOID)pszOutBuffer,
                        dwSize, &dwDownloaded ) )
                    printf( "Error %u in WinHttpReadData.\n", GetLastError( ) );
                else
                    printf( "%s", pszOutBuffer );

                // Free the memory allocated to the buffer.
                delete [] pszOutBuffer;
            }
        } while( dwSize > 0 );
    }


    // Report any errors.
    if( !bResults )
        printf( "Error %d has occurred.\n", GetLastError( ) );

    // Close any open handles.
    if( hRequest ) WinHttpCloseHandle( hRequest );
    if( hConnect ) WinHttpCloseHandle( hConnect );
    if( hSession ) WinHttpCloseHandle( hSession );

    return 0;
}