WinHttp error 12030 after call to SharePoint

Dec 19, 2014 at 9:36 AM
Edited Dec 19, 2014 at 9:36 AM
I've got "WinHttpSendRequest: 12030: The connection with the server was terminated abnormally" when call to SharePoint 2013 service via cpprest, but when I make same request via browser everything works OK.
It appears in
cpprest110d_2_3.dll!web::http::client::details::winhttp_client::completion_callback(void * hRequestHandle, unsigned __int64 context, unsigned long statusCode, void * statusInfo, unsigned long statusInfoLength)
{
    ...
    if(p_request_context != nullptr)
    {
        switch (statusCode)
        {
        case WINHTTP_CALLBACK_STATUS_REQUEST_ERROR :
    ...
}
Here is my code:
http_client_config config;
config.set_credentials(credentials(U("login"), U("password")));
http_client client(U("http://myserver.com/"), config);
http_request request;
request.set_method(methods::GET);
request.set_request_uri(web::uri::encode_uri(U("/_vti_bin/ListData.svc")));
auto task = client.request(request);
task.wait(); // exception is here
Can someone advice me how to detect the reason of different responses for cpprest and browser cases?
Dec 20, 2014 at 2:13 AM
Hi fruler,

If you have a public server that I can test/reproduce a request against I could maybe try to have a deeper look. You could use a debugging proxy like Fiddler to take a look and see if the out-going request is any different in the C++ Rest SDK vs. your browser.

Steve
Dec 21, 2014 at 8:36 AM
Edited Dec 21, 2014 at 2:04 PM
Unfortunately the server is not public (at least there is no public login/passwrod). The requests are pretty different since I send a minimal portion of data (maybe insufficient?) while browser sends LOTS !

my app:
GET http://myserver.com/_vti_bin/ListData.svc HTTP/1.1
Accept: application/json; odata=verbose
User-Agent: cpprestsdk/2.3.0
Connection: Keep-Alive
Host: myserver.com


HTTP/1.1 504 Fiddler - Receive Failure
Content-Type: text/html; charset=UTF-8
Connection: close
Timestamp: 09:18:54.307

[Fiddler] ReadResponse() failed: The server did not return a response for this request.
browser (I've changed long data strings with <some data>):
GET http://myserver.com/_vti_bin/lists.asmx HTTP/1.1
Host: myserver.com
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:34.0) Gecko/20100101 Firefox/34.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Cookie: __utma=<some data>
Connection: keep-alive
Cache-Control: max-age=0


HTTP/1.1 401 Unauthorized
Content-Type: text/plain; charset=utf-8
Server: Microsoft-IIS/8.0
SPRequestGuid: 55ded79c-bf98-d062-6b3c-e7a84eeef6ff
request-id: 55ded79c-bf98-d062-6b3c-e7a84eeef6ff
X-FRAME-OPTIONS: SAMEORIGIN
SPRequestDuration: 4
SPIisLatency: 1
WWW-Authenticate: NTLM
X-Powered-By: ASP.NET
MicrosoftSharePointTeamServices: 15.0.0.4569
X-Content-Type-Options: nosniff
X-MS-InvokeApp: 1; RequireReadOnly
Date: Sun, 21 Dec 2014 07:21:01 GMT
Content-Length: 16
Cache-Control: proxy-revalidate
Connection: Keep-Alive
Set-Cookie: BCSI-CS-65159be231348f46=1; Path=/
Proxy-Support: Session-Based-Authentication

401 UNAUTHORIZED

------------------------------------------------------------------

GET http://myserver.com/_vti_bin/lists.asmx HTTP/1.1
Host: myserver.com
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:34.0) Gecko/20100101 Firefox/34.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Cookie: __utma=<some data>
Connection: keep-alive
Cache-Control: max-age=0
Authorization: NTLM <some data>


HTTP/1.1 401 Unauthorized
Server: Microsoft-IIS/8.0
WWW-Authenticate: NTLM <some data>
SPRequestGuid: 55ded79c-8fa1-d062-6b3c-e185295c6788
request-id: 55ded79c-8fa1-d062-6b3c-e185295c6788
X-FRAME-OPTIONS: SAMEORIGIN
SPRequestDuration: 2
SPIisLatency: 1
X-Powered-By: ASP.NET
MicrosoftSharePointTeamServices: 15.0.0.4569
X-Content-Type-Options: nosniff
X-MS-InvokeApp: 1; RequireReadOnly
Date: Sun, 21 Dec 2014 07:21:01 GMT
Content-Length: 0
Cache-Control: proxy-revalidate
Connection: Keep-Alive
Set-Cookie: BCSI-CS-65159be231348f46=1; Path=/
Proxy-Support: Session-Based-Authentication



------------------------------------------------------------------

GET http://myserver.com/_vti_bin/lists.asmx HTTP/1.1
Host: myserver.com
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:34.0) Gecko/20100101 Firefox/34.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Cookie: __utma=<some data>
Connection: keep-alive
Cache-Control: max-age=0
Authorization: NTLM <some data>

HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
Vary: Accept-Encoding
Server: Microsoft-IIS/8.0
X-SharePointHealthScore: 0
X-AspNet-Version: 4.0.30319
SPRequestGuid: 55ded79c-5fa9-d062-6b3c-ef24c9fc6c3d
request-id: 55ded79c-5fa9-d062-6b3c-ef24c9fc6c3d
X-FRAME-OPTIONS: SAMEORIGIN
SPRequestDuration: 25
SPIisLatency: 1
Persistent-Auth: true
X-Powered-By: ASP.NET
MicrosoftSharePointTeamServices: 15.0.0.4569
X-Content-Type-Options: nosniff
X-MS-InvokeApp: 1; RequireReadOnly
Date: Sun, 21 Dec 2014 07:21:01 GMT
Content-Length: 1626
Cache-Control: private, max-age=0, proxy-revalidate
Connection: Keep-Alive
Content-Encoding: gzip
<some data>
I used credentials with valid user/password when created cpprest client, but it seems that I need some complex authentication model - cpprest does not send my authentication data.
Dec 21, 2014 at 2:02 PM
I have implemented WinInet analog and it works:
#include <windows.h>
#include <wininet.h>
#pragma comment(lib, "wininet.lib")
#include <iostream>

void main()
{
    HINTERNET hOpenHandle,  hConnectHandle, hResourceHandle;

    hOpenHandle = InternetOpenA("Example", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
    hConnectHandle = InternetConnectA(hOpenHandle, "myserver.com", INTERNET_INVALID_PORT_NUMBER, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0);

    LPCSTR accept_types[] = {"application/json", "text/*", 0};
    hResourceHandle = HttpOpenRequestA(hConnectHandle, "GET", "/_vti_bin/ListData.svc", NULL, NULL, NULL, INTERNET_FLAG_KEEP_CONNECTION, 0);

resend:
    HttpSendRequestA(hResourceHandle,0,0,0,0);

    DWORD dwStatus;
    DWORD dwStatusSize = sizeof(dwStatus);
    HttpQueryInfoA(hResourceHandle, HTTP_QUERY_FLAG_NUMBER | HTTP_QUERY_STATUS_CODE, &dwStatus, &dwStatusSize, NULL);
    if (dwStatus == HTTP_STATUS_DENIED)
    {
        std::string server_login = "login";
        std::string server_password = "password";
        InternetSetOptionA(hResourceHandle, INTERNET_OPTION_USERNAME, (LPVOID)server_login.c_str(), server_login.size() + 1);
        InternetSetOptionA(hResourceHandle, INTERNET_OPTION_PASSWORD, (LPVOID)server_password.c_str(), server_password.size() + 1);
        goto resend;
    }

    char b[80000];
    DWORD d = 0;
    while (InternetReadFile(hResourceHandle, b, sizeof(b), &d) && d == sizeof(b))
        std::cout.write(b, d);

    std::cout.write(b, d);
    InternetCloseHandle(hResourceHandle);
}
Same OK if using InternetErrorDlg instead of InternetSetOptionA
Dec 24, 2014 at 12:02 AM
Hi fruler,

Authentication works by not sending any credentials unless challenged. This is the standard convention. The credentials won't be sent until a HTTP 401 unauthorized is encountered. According to fiddler you are getting a 504 gateway timeout. Perhaps you are having some proxy issues?

Other miscellaneous notes: I notice in your code you are making requests to different locations. Sometimes http://myserver.com/_vti_bin/ListData.svc in others http://myserver.com/_vti_bin/lists.asmx. You also are using different values in your requests for the Accept request header.

Steve
Dec 24, 2014 at 7:05 AM
I was mistaken about lists.asmx - ListData.svc should be used in both cases.

Nevertheless, the situation is follow:
Casablanca: create client with proper proxy and site credentials, send request - as a result, HTTP 504 is returned, no authentication requests are sent according to Fiddler
Browser: proxy and site credentials are cached (or requested via dialog), request is sent - HTTP 200, authentication is sent according to Fiddler
Native WinInet application: request is sent, HTTP 401 is gotten, proxy/site credentials are set, request is re-sent - HTTP 200

The problem is that I didn't see the place where casablanca even tries to send credentials. Maybe because it gets HTTP 504 instead of HTTP 401 (like WinInet gets)? Then I cannot understand why site responses HTTP 401 to WinInet but HTTP 504 to casablanca. Does casablanca do something else than WinInet code above?
Dec 30, 2014 at 11:46 PM
Hi fruler,

The C++ Rest SDK is not going to send the credentials unless and HTTP 401 status code is encountered. I would try to figure out way you are getting back a 504 status code, because this is the reason the credentials are not being resent.

Steve
Jan 2, 2015 at 9:54 AM
Edited Jan 2, 2015 at 10:04 AM
Hi Steve,

Maybe this will help you
  • I work via proxy (client -> my proxy -> remote host)
  • When I use WinInet, I get HTTP 401 as described, but if I put Fiddler as a proxy to catch the traffic (client -> Fiddler -> my proxy -> remote host), sometimes Fiddler shows responded HTTP 504 instead of HTTP 401 for the same request. If I reset local proxy settings (back to scheme client -> my proxy -> remote host), everything becomes fine (request, responded HTTP 401, request with credentials, responded HTTP 200)
  • Sometimes when I use WinInet directly (client -> my proxy -> remote host), I get HTTP 307 with response text "Switch to virtual host" and "Location" referencing some intranet address. If I send site credentials there, I permanently get HTTP 401. Browser is able to handle this situation. Now I am trying to play with this case.
  • I saw you use WinHttp (not WinInet). I tried to launch http://msdn.microsoft.com/en-us/library/windows/desktop/aa383144%28v=vs.85%29.aspx code and did not succeed (I've got HTTP 401 even after re-sending credentials). Trying to figure out why.
Thank you for responses