Azure / azure-relay-dotnet

☁️ .NET Standard client library for Azure Relay Hybrid Connections

Home Page:https://docs.microsoft.com/en-us/azure/service-bus-relay/relay-what-is-it

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

HybridConnection for HttpRequest on rendezvous url: The FIN flag of the last frame of the big post body(>64kb) is not set.

Neilpang opened this issue · comments

commented

Actual Behavior

  1. The FIN flag of the Last Websocket frame of the post body is NOT set.

Expected Behavior

  1. The FIN flag of the Websocket frame of the post body is set.

I was writing my own AzureRelayListener implementation, As in the spec here: https://docs.microsoft.com/en-us/azure/service-bus-relay/relay-hybrid-connections-protocol#request-message-1

The Fin flag of the last binary frame of the post body should be set.

This is ok for normal inline request(body < 64kB).

But with body > 64KB, when I connect to the rendezvous address to read the request, the first json frame is good. It's ok to read all the POST body(> 64kB) data frames, but the FIN flag of the last Frame is NOT set.

From the http client side, I used curl to POST file:

The file size is 100kB= 102400 Bytes

curl -vv  -H ServiceBusAuthorization:"SharedAccessSignature sr=sb%3a%2f%2fxxxxxxxxx%2fhc1&sig=xxxxxxxxxxxx&skn=RootManageSharedAccessKey"  \
https://xxxxxx.servicebus.windows.net/xxxxx1      \
--data-binary @100kb.dat

> POST /xxx1 HTTP/1.1
> Host: xxxxxxx.servicebus.windows.net
> User-Agent: curl/7.47.0
> Accept: */*
> ServiceBusAuthorization:SharedAccessSignature sr=sb%3a%2f%2xxxxxxxx%2fhc1&sig=xxxxxxxskn=RootManageSharedAccessKey
> Content-Length: 102400
> Content-Type: application/x-www-form-urlencoded
> Expect: 100-continue
> 
* Done waiting for 100-continue
* We are completely uploaded and fine

The client is even setting "Content-Length" value.

But from the Listener side, I received 3 body frames:

Log: AzureRelayListenerLog:[Body]EOM=False Length:32768
Log: AzureRelayListenerLog:[Body]EOM=False Length:32768
Log: AzureRelayListenerLog:[Body]EOM=False Length:32768
Log: AzureRelayListenerLog:[Body]EOM=False Length:4096 

The total size is 32768*3+4096 = 102400, which is ok. but the EOM(FIN) flag of every frame are NON-SET(false) for me.

It is expected that the EOM(FIN) flag of the last frame is SET. so that I know it's the request ending.

This caused trouble for me, I don't know when to stop. Because the content-length header is swallowed by AzureRelay. I don't know how many bytes the body contains.

This can also be a problem in the official sample code here:
https://github.com/Azure/azure-relay/blob/master/samples/hybrid-connections/dotnet/simple-http/Server/Program.cs#L43

if I insert the code to read the inputStream.length property, it hangs.

 // Provide an HTTP request handler
            listener.RequestHandler = (context) =>
            {
                Console.WriteLine(context.Request.Headers);

               // reading Length property makes it hang here.
                Console.WriteLine("context.Request.InputStream.Length=" + context.Request.InputStream.Length);

Thanks.

The end of the HTTP Request body will be indicated with one additional WebSocket fragment/packet with 0 bytes and EOM == true. Here's an example when I send/receive 100K

Listener: Received Type = Text, EOM = True, Count = 612: {"request":{ ... , "body":true } }
Listener: Received Type = Binary, EOM = False, Count = 16380
Listener: Received Type = Binary, EOM = False, Count = 16384
Listener: Received Type = Binary, EOM = False, Count = 4
Listener: Received Type = Binary, EOM = False, Count = 16380
Listener: Received Type = Binary, EOM = False, Count = 16384
Listener: Received Type = Binary, EOM = False, Count = 4
Listener: Received Type = Binary, EOM = False, Count = 16380
Listener: Received Type = Binary, EOM = False, Count = 16384
Listener: Received Type = Binary, EOM = False, Count = 4
Listener: Received Type = Binary, EOM = False, Count = 4096
Listener: Received Type = Binary, EOM = True, Count = 0

Are you able to receive more more packet off the wire indicating Binary, 0 bytes, and EOM=true?

With the Microsoft provided library you should be able to call context.Request.InputStream.Read until that Read call returns 0 bytes read. That's how one reads to the end of a non-seekable Stream in .NET.

Regarding the context.Request.InputStream.Length hanging is that with the Microsoft provided library or yours? Technically since the Stream of a large message should report CanSeek==false calling get_Length should throw a NotSupportedException. If the Microsoft library's InputStream doesn't report CanSeek == false and throw NotSupportedException when request body is > 64KB then an issue should be created to fix this.

Also if you're forking your library from Microsoft.Azure.Relay.dll (https://github.com/Azure/azure-relay-dotnet) make sure you pick from the the latest version of dev branch right now. It will be merged into master soon with the next release.

commented

@dlstucki Thanks a lot.

I will try again, and update this thread later.

Regarding the context.Request.InputStream.Length hanging is that with the Microsoft provided library or yours?

It's the official lib, not mine.
https://github.com/Azure/azure-relay/blob/master/samples/hybrid-connections/dotnet/simple-http/Server/Program.cs#L43

Thanks.

commented

@dlstucki It works. thanks.