QWebSocket can't process the handshake - c++

I have a problem with establishing a WebSocket connection using QWebSocket. I'm using Qt 5.6 and its QWebSocket implementation. I'm sure that server works right and uses WS v13 protocol. It works fine with all browsers. When I try to connect to the server, QWebSocket emits error and stateChanged signals with these messages (I get them using errorString() method):
QWebSocketPrivate::processHandshake: Connection closed while reading header.
Invalid statusline in response: Upgrade: websocket
Invalid statusline in response: Connection: Upgrade
Invalid statusline in response: Sec-WebSocket-Accept: HLaITyncgax+CH7OUIXnsCfFDDY=
Invalid statusline in response: // there's a carriage return symbol
Although it says Connection closed while reading header, connection isn't actually closed (because server sends additional packets through websocket after a while). I've tested my application on websocket.org's echo test and it works fine! But I sniffed the packets on both tries and didn't find any significant differences.
Result of packet sniffing on the server which I try to connect to:
GET / HTTP/1.1
Host: <hostname>:6670
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: WcIsYc1AZ6CKikXFwGXgMg==
Origin: http://<hostname>
Sec-WebSocket-Version: 13
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:45.0) Gecko/20100101 Firefox/45.0
Connection: keep-alive, Upgrade
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: 7lfSGmSz/eW1mSzaMnuzOqg00w4=
Result of packet sniffing on connection with echo.websocket.org:
GET / HTTP/1.1
Host: echo.websocket.org:80
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: MUAZoP0Ef4KSWkmtsB5YDw==
Origin: http://<hostname>
Sec-WebSocket-Version: 13
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:45.0) Gecko/20100101 Firefox/45.0
Connection: keep-alive, Upgrade
HTTP/1.1 101 Web Socket Protocol Handshake
Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: content-type
Access-Control-Allow-Headers: authorization
Access-Control-Allow-Headers: x-websocket-extensions
Access-Control-Allow-Headers: x-websocket-version
Access-Control-Allow-Headers: x-websocket-protocol
Access-Control-Allow-Origin: http://<hostname>
Connection: Upgrade
Date: Thu, 31 Mar 2016 12:05:49 GMT
Sec-WebSocket-Accept: c4yAe+A1VRuhF1LSC/TGgPoa8N4=
Server: Kaazing Gateway
Upgrade: websocket
<data exchange goes here normally>
What should I do to investigate and fix the problem? I have no access to the server.
P.S. Yes, I'm aware of QTBUG-40878. It affects Qt 5.3.1 but I use 5.6.0 and it has been obviously fixed in my Qt setup.

This may be QTBUG-51069 (which is not the one you mentioned):
If there is a delay between status line ("HTTP/1.1 101 Upgrading Protocol") and headers, QWebSocketPrivate::processHandshake erroneously detects server disconnect. The problem is that disconnect condition is checked using QAbstractSocket::atEnd function which just checks if data available and not the actual socket state. This results in multiple error signals:
websocket error: QWebSocket::processHandshake: Connection closed while reading header.
websocket error: Invalid statusline in response: Date: Thu, 11 Feb 2016 20:07:37 GMT^M .
websocket error: Invalid statusline in response: Server: WSGIServer/0.1 Python/2.7.10^M .
websocket error: Invalid statusline in response: Upgrade: websocket^M .
websocket error: Invalid statusline in response: Connection: Upgrade^M .
websocket error: Invalid statusline in response: Sec-WebSocket-Accept: oQ+NK56UdGrsXFisB9chjE3SU+Y=^M .
websocket error: Invalid statusline in response: Sec-WebSocket-Version: 13^M .
websocket error: Invalid statusline in response: Content-Length: 0^M .
websocket error: Invalid statusline in response: ^M .
The fix is in Qt 5.6.2.
For Qt 5.7, judging from the commit history I think it will be in 5.7.1.

Related

Blazor Server Side - Frequent 504 errors in AWS environment

After deploying a blazor server side project to an Amazon Web Services environment via AWS Elastic Beanstalk, the website experiences frequent disconnects that I do not understand.
These disconnects do not happen locally when testing.
Errors:
[2020-04-30T16:29:18.326Z] Error: Connection disconnected with error 'Error'.
and
Failed to load resource: the server responded with a status of 504 ()
The request causing the 504 errors has a header like so:
Request URL: https://mywebserver/_blazor?id=UOPQELxzuEcaGbpNUQA01Q&_=1588264098305
Request Method: GET
Status Code: 504
Remote Address: 3.11.236.203:443
Referrer Policy: no-referrer-when-downgrade
content-length: 550
content-type: text/html
date: Thu, 30 Apr 2020 16:29:20 GMT
server: awselb/2.0
status: 504
:authority: mywebserver
:method: GET
:path: /_blazor?id=UOPQELxzuEcaGbpNUQA01Q&_=1588264098305
:scheme: https
accept: */*
accept-encoding: gzip, deflate, br
accept-language: en-GB,en-US;q=0.9,en;q=0.8
content-type: text/plain;charset=UTF-8
sec-fetch-dest: empty
sec-fetch-mode: cors
sec-fetch-site: same-origin
user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36
x-requested-with: XMLHttpRequest
This issue seems remarkably similar to a Github issue posted here, that is currently being investigated by Microsoft, although this issue is not AWS-related: https://github.com/dotnet/aspnetcore/issues/19094
Any help would be vastly appreciated!
i managed to fix this in the end.
Apparently the issue was caused by the use of LongPolling. LongPolling issues requests and waits 100 seconds before cancelling the request. By setting the timeout to be greater than the default of 60 seconds in the Elastic Load Balancer in my AWS settings, the disconnects stopped. 110 seconds was recommended as a safe timeout value.
Issue on Asp.NET github that I opened for those interested: https://github.com/dotnet/aspnetcore/issues/21369

invoking a SOAP webservice with telnet command

I came across a situation where I have to invoke a SOAP webservice (deployed in another server) from one of the production server manually and check whether everything is fine.
as these are all live servers there are no network tools like wget, curl and nc are available. I tried checking for a solution is google but no luck.
As a workaround I can write a java client socket and invoke the service but even that is not allowed in here.
telnet is there but am not sure how to make it work for my case.
Is there any other way to invoke remote services without these tools?
After trying few hours finally, I was able to invoke SOAP service with telnet as below
first open a TCP connection to the remote server as below.
$> telnet hostname portname
Once it is connected, frame a request as one of the below methods and paste on the screen and press enter key two times.
There are two ways we can call a service.
Method 1: instead of mentioning endpoint path in POST header, we can give it in SOAPAction header.
POST / HTTP/1.1
Accept-Encoding: gzip,deflate
Content-Type: text/xml;charset=UTF-8
SOAPAction: "<endpoint URL from WSDL>"
Content-Length: <number of bytes you are sending in body section>
Host: <hostname>:<port>
Proxy-Connection: Keep-Alive
User-Agent: Apache-HttpClient/4.1.1 (java 1.5)
<SOAP Request payload>
Method 2: mentioning endpoint path in the request header itself, so we can give empty value in "" SOAPAction header (it means request path itself is the Endpoint path).
POST /soap/server HTTP/1.1
Accept-Encoding: gzip,deflate
Content-Type: text/xml;charset=UTF-8
SOAPAction: ""
Content-Length: <payload size>
Host: hostname:port
Proxy-Connection: Keep-Alive
User-Agent: Apache-HttpClient/4.1.1 (java 1.5)
<SOAP Request payload>
Response: Once the call invoked successfully, the response will be printed as below
HTTP/1.1 200 OK
Content-Type: text/xml;charset=UTF-8
Content-Length: <response payload size>
<SOAP response payload>
For more information on SOAPHeader check this link
Note: Make sure the length of the request payload is correct before sending it.

HTTPS Keep-Alive to reduce handshake time

So I have an app that make several requests to the server on a button click.
I noticed there's HTTPS handshake overhead for every single call.
How can I re-use the connection in this case so there's no need of handshake overhead on each back-to-back request?
POST https://myserver:8080/Service/GetContact HTTP/1.1
Accept: text/html,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5
Content-Type: application/json
Content-Length: 113
Host: myserver:8080
Connection: Keep-Alive
I thought Connection: Keep-Alive is suppose to take care of that for me?

MS Http Server API (< Win 8) and WebSockets

I try to realize WebSocket protocol at MS Http Server API under win server 2008 (haven't HTTP_SEND_RESPONSE_FLAG_OPAQUE flag).
HTTP_RESPONSE response={0};
const char upgrade_val[]="Websocket";
response.Headers.KnownHeaders[HttpHeaderUpgrade].RawValueLength=strlen(upgrade_val);
response.Headers.KnownHeaders[HttpHeaderUpgrade].pRawValue =upgrade_val;
const char connection_val[]="Upgrade";
response.Headers.KnownHeaders[HttpHeaderConnection].RawValueLength=strlen(connection_val);
response.Headers.KnownHeaders[HttpHeaderConnection].pRawValue =connection_val;
HTTP_UNKNOWN_HEADER unknown[1];
response.Headers.UnknownHeaderCount=1;
response.Headers.pUnknownHeaders =unknown;
const char accept_name[]="Sec-WebSocket-Accept";
unknown[0].NameLength =_countof(accept_name)-1;
unknown[0].pName =accept_name;
unknown[0].RawValueLength=HANDSHAKE_KEY_LENGTH;
unknown[0].pRawValue =base64_key;
response.Version.MajorVersion=1;
response.Version.MinorVersion=1;
response.StatusCode =HTTP_SWITCHING_PROTOCOLS;
const char reason[] ="Switching Protocols";
response.ReasonLength =strlen(reason);
response.pReason =reason;
HttpSendHttpResponse(iocp,RequestId,HTTP_SEND_RESPONSE_FLAG_MORE_DATA,&raw_response,NULL,NULL,NULL,NULL,NULL,NULL);
Browser send header (from Fiddler)
GET http://server.host/ HTTP/1.1
Upgrade: websocket
Connection: Upgrade
Host: server.host
Origin: null
Pragma: no-cache
Cache-Control: no-cache
Sec-WebSocket-Key: V86c1TFOwWfZqhS42C0arA==
Sec-WebSocket-Version: 13
Sec-WebSocket-Extensions: x-webkit-deflate-frame
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.94 Safari/537.36
server's response (from Fiddler)
HTTP/1.1 101 Switching Protocols
Upgrade: Websocket
Server: Microsoft-HTTPAPI/2.0
Sec-WebSocket-Accept: 3io2SU7uJIeFlwy0+OFJUDNrA44=
Date: Tue, 28 May 2013 09:27:59 GMT
EndTime: 13:27:59.006
ReceivedBytes: 0
SentBytes: 0
and browser shows 1016 error.
Assuming your Sec-WebSocket-Accept header value is calculated correctly, and assuming your response variable is supposed to be named raw_response instead, then your response is missing the required Connection: Upgrade header despite your code assigning a value for it.
HTTP_SEND_RESPONSE_FLAG_OPAQUE (Windows 8 and later) is required for WebSockets.
WebSocket servers on Windows Server (2011-12-20)
As it stands right now, Server 2008/R2 boxes cannot host WebSockets.
At least, not whilst sharing ports 80 and 443 with IIS web server
Re: [hybi] WebSocket protocol as it stands (2010-11-06)
we need to tweak http.sys to recognize what is really a non-HTTP
request, as an HTTP request

qt soap client + ASP.net Web service

I'm writing Qt client for ASP.NET web service with FORMS based authentication.
The service consists of 3 methods:
Login(user,pass)
Helloworld() - this method returns info about authenticated user.
Logout()
Every thing working fine on the dot.net client with CookieContainer.
The problem begins with HelloWorld() methods. it returns null because I can't access server session.
I'm doing the following:
from the response of Login() request I'm getting the cookies which are sent to client:
QNetworkAccessManager *manager = http.networkAccessManager();
cookie = manager->cookieJar();
When sending the second soaprequest for HelloWorld method I adding these cookies
to QtSoapHttpTransport http:
http.networkAccessManager()->setCookieJar(cookie)
but the request which is going from server is empty.
I moved further with my investigation and monitored HTTP traffic coming to server from Qt client and .NET client.
The HTTP Header for both SOAP requests are different:
This is Request coming from .NET client
POST /test/service1.asmx HTTP/1.1
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; MS Web Services Client Protocol 2.0.50727.3053)
VsDebuggerCausalityData: uIDPoyhZznNkbItPkJSR3EA+zEIAAAAAUkpe7URduE6nmhnT8f uQeqCQBMlX0zxCm65yW4ZPBkUACQAA
Content-Type: text/xml; charset=utf-8
SOAPAction: "http://localhost/test/HelloWorld"
Host: localhost:8080
Cookie: MyAuthenCookie=DC7620DA79E080FECA37AC6866BF2690D57 B37443506F0D7EEA9DF209827360894D80D37E1B121D73EE44 766BDAEE16BA3FB0E8B95ADB1252AB00A76706930ACDC87CF9 F26744B7E9E3EB7FBB3812997
Content-Length: 291
Expect: 100-continue
and this is Request coming from Qt SOAP client:
POST /test/Service1.asmx HTTP/1.1
Content-Type: text/xml;charset=utf-8
SOAPAction: http://localhost/test/HelloWorld
Content-Length: 350
Cookie: MyAuthenCookie=9AFB2B22EE78D19DFD52BD2193A3D71627C F7303C15E4354E43CC2F31AECBDFFAD09176AA45F33B35C3C3 73891F1FE994580E8EE70FD4D01507670743138E74E152CFF4 EB3C37D90D3A7A0E272A804C3
Connection: Keep-Alive
Accept-Encoding: gzip
User-Agent: Mozilla/5.0
Host: localhost:8080
Does any body have any idea what might be the problem and hoe to solve it?
How can I modify Headers for HTTP POST request in QtSoapHttpTransport object in order to make it identical to .NET request?
Thank you in advance,
Danny.
Are you running IIS or the ASP.NET Development server?
I was able to recreate a similar problem where everything worked fine using ASP.NET Development server but under IIS the session was null.
One thing to look for is when you invoke the session-enabled-service you should see the ASP.NET_SessionId being set in the response headers
Set-Cookie: ASP.NET_SessionId=5vxqwy45waoqma45lbbozj45; path=/; HttpOnly
Set-Cookie: MyAuthenCookie=510969D70201B358F8B0BBEEE7E79316B7ABCCC74312B0BD678DA4BE90E5C51CD6E7CDCA486DDB41BCBF489DB7280B3B979FD70B78D7F63B03C33431ADDAFDCA; expires=Mon, 07-Dec-2009 06:41:04 GMT; path=/; HttpOnly
To get sessions working under IIS, I had to add the following to web.config under system.web:
<sessionState mode="InProc" cookieless="false" timeout="20" />
<httpModules>
<add name="Session" type="System.Web.SessionState.SessionStateModule"
</httpModules>
This was under Windows 2003.