代码之家  ›  专栏  ›  技术社区  ›  Simon Linder

用C++C++获取重定向信息

  •  0
  • Simon Linder  · 技术社区  · 15 年前


    我做错什么了?我正在尝试从我用来验证用户身份的服务器获取重定向信息。这与我的C代码很好,但是我不能让我的C++代码工作。
    下面是工作代码:

    string postData = @"username=myUsername&serviceID=someServiceId&password=somePassword";
    byte[] postBytes = Encoding.UTF8.GetBytes(postData);
    
    // create the proper HttpWebRequest
    HttpWebRequest request = (HttpWebRequest)WebRequest.Create(@"https://myAuthServer.com/login");
    
    request.Method = "POST";
    request.ContentType = "application/x-www-form-urlencoded";
    request.Accept = "utf-8";
    request.ContentLength = postBytes.Length;
    request.PreAuthenticate = true;
    request.AllowAutoRedirect = false;
    
    // now get the information from the login server
    Stream requestStream = request.GetRequestStream();
    HttpWebResponse response = null;
    
    // post the data
    requestStream.Write(postBytes, 0, postBytes.Length);
    
    // get the response and get the wanted information
    response = (HttpWebResponse)request.GetResponse();
    
    const string Session = "?session=";
    
    Uri location = new Uri(response.Headers["Location"]);
    m_redirect = location.Host + location.LocalPath;
    m_authentificationId = location.Query.Substring(Session.Length);
    

    我使用这些信息进行进一步的认证。一切都很好。

    现在我想用C++代码做同样的事情。但是这个代码不起作用。
    所以这里是:

    HINTERNET hOpen, hConnect, hReq;
    hOpen = InternetOpen(_T(""), INTERNET_OPEN_TYPE_DIRECT, _T(""), _T(""), 0);
    if(!InternetHandleValid(hOpen))
    {
        return false;
    }
    
    hConnect = InternetConnect(hOpen, _T("myAuthServer.com"),
        INTERNET_DEFAULT_HTTPS_PORT, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0);
    if(!InternetHandleValid(hConnect))
    {
        return false;
    }
    
    hReq = HttpOpenRequest(hConnect, _T("POST"), _T("/login"), NULL, NULL,
        NULL, INTERNET_FLAG_NO_AUTO_REDIRECT | INTERNET_FLAG_SECURE, 0);
    
    if(!InternetHandleValid(hReq))
    {
        return false;
    }
    
    if (!HttpAddRequestHeaders(hReq, _T("Content-Type: application/x-www-form-urlencoded"), -1L, HTTP_ADDREQ_FLAG_ADD))
    {
        return false;
    }
    
    if (!HttpAddRequestHeaders(hReq, _T("Expect: 100-continue"), -1L, HTTP_ADDREQ_FLAG_ADD))
    {
        return false;
    }
    
    if (!HttpAddRequestHeaders(hReq, _T("Connection: Keep-Alive"), -1L, HTTP_ADDREQ_FLAG_ADD))
    {
        return false;
    }
    
    if (!HttpAddRequestHeaders(hReq, _T("Accept: utf-8"), -1L, HTTP_ADDREQ_FLAG_ADD))
    {
        return false;
    }
    
    CString cstrPostData = _T("username=myUsername&serviceID=someServiceId&password=somePassword");
    
    char buffer[10];
    _itoa_s(cstrPostData.GetLength(), buffer, 10, 10);
    CString cstrContentLength(buffer);
    
    if (!HttpAddRequestHeaders(hReq, _T("Content-Length: ") + cstrContentLength, -1L, HTTP_ADDREQ_FLAG_ADD))
    {
        return false;
    }
    
    LPVOID lpData = (LPVOID)cstrPostData.GetBuffer(cstrPostData.GetLength());
    if(HttpSendRequest(hReq, NULL, -1L, lpData, wcslen(cstrPostData)))
    {
        DWORD dwCode, dwCodeSize; 
        dwCodeSize = sizeof(DWORD);
        if(!HttpQueryInfo(hReq, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER, &dwCode, &dwCodeSize, NULL))
        {
            return false;
        }
    
        // we need to have the 302 (Redirect) here
        if (dwCode != 302)
        {
            return false;
        }
    
        wchar_t chData[1024] = _T("\0");
        DWORD dwBuffer = 1023;
        if(!HttpQueryInfo(hReq, HTTP_QUERY_RAW_HEADERS_CRLF, (LPVOID)chData, &dwBuffer, NULL))
        {
            return false;
        }
    
        CStringA cstrHeaders(chData);
        bool b = ExtractRedirectAndSessionFromHeader(cstrHeaders);
    }
    

    现在的问题是我 Location: https://myAuthServer.com/centrallogin-2.2/error.jsp 所以没有适当的重定向和会话。我已经发现,当我不设置时,我的C代码中也会出现这个错误。 request.ContentType 适当地。但我确实在C++代码中设置了内容类型的标题。所以我不知道我做错了什么。
    还有什么想法吗?
    编辑:
    好的,我也用WinHTTP API尝试过。以下是我的代码:

    HINTERNET hSession = NULL, hConnect = NULL, hRequest = NULL;
    
    // Use WinHttpOpen to obtain a session handle.
    hSession = WinHttpOpen(NULL, WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME,
        WINHTTP_NO_PROXY_BYPASS, 0);
    
    hConnect = WinHttpConnect(hSession, L"myAuthServer.com", INTERNET_DEFAULT_HTTPS_PORT, 0);
    hRequest = WinHttpOpenRequest(hConnect, L"POST", L"/login", NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, WINHTTP_FLAG_SECURE);
    
    // disable auto redirects
    DWORD dwOptionValue = WINHTTP_DISABLE_REDIRECTS;
    BOOL b = WinHttpSetOption(hRequest, WINHTTP_OPTION_DISABLE_FEATURE, &dwOptionValue, sizeof(dwOptionValue));
    
    static const WCHAR szContentType[] = L"Content-Type: application/x-www-form-urlencoded\r\n";
    b = WinHttpAddRequestHeaders(hRequest, szContentType, (DWORD)-1, WINHTTP_ADDREQ_FLAG_ADD & WINHTTP_ADDREQ_FLAG_REPLACE);
    
    CString cstrPostData = _T("username=myUsername&serviceID=someServiceId&password=somePassword");
    b = WinHttpSendRequest(hRequest, WINHTTP_NO_ADDITIONAL_HEADERS, -1L, WINHTTP_NO_REQUEST_DATA, 0, wcslen(cstrPostData), 0);
    
    DWORD dwBytesWritten = 0;
    b = WinHttpWriteData(hRequest, cstrPostData, wcslen(cstrPostData), &dwBytesWritten);
    
    b = WinHttpReceiveResponse(hRequest, NULL);
    
    DWORD dwSize = sizeof(DWORD);
    DWORD dwStatusCode = 0;
    b = WinHttpQueryHeaders(hRequest, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, NULL, &dwStatusCode,
        &dwSize, WINHTTP_NO_HEADER_INDEX);
    
    wchar_t chData[1024] = _T("\0");
    DWORD dwBuffer = 1023; 
    b = WinHttpQueryHeaders(hRequest, WINHTTP_QUERY_RAW_HEADERS_CRLF, NULL, (LPVOID)chData, &dwBuffer, NULL);
    CStringA cstrHeaders(chData);
    
    WinHttpCloseHandle(hSession);
    WinHttpCloseHandle(hConnect);
    WinHttpCloseHandle(hRequest);
    
    cstrPostData.ReleaseBuffer();
    

    所以重定向URL和会话ID应该在chdata中。但结果还是错了。我也试过了Wireshark。因为这都是HTTPS,所以我无法从中读取太多内容。我唯一能比较的就是帧的数量等。当使用winhttp时,wireshark日志看起来很相似。所以我认为这是更好的方法。
    还有什么想法吗?

    2 回复  |  直到 15 年前
        1
  •  1
  •   anon    15 年前

    引述 the MSDN page 对于此功能:

    指向字符串变量的指针 包含要附加到的标题 请求。每个标题必须 由CR/LF(运输)终止 回程/换行)对。

    因此您的字符串需要以\r\n

        2
  •  0
  •   Simon Linder    15 年前

    好吧,我终于修好了。问题是我的post数据字符串 CString cstrPostData 被解释为 CStringW . 所以发送的数据就是问题所在。当我显式地将post数据字符串更改为 CStringA cstrPostData 一切都是正确的。