* Handling HTTP "Upgrade" requests
@ 2015-02-21 23:00 David Thompson
2015-02-25 5:05 ` Nala Ginrut
2015-03-04 10:51 ` Ludovic Courtès
0 siblings, 2 replies; 7+ messages in thread
From: David Thompson @ 2015-02-21 23:00 UTC (permalink / raw)
To: guile-devel
I've been tinkering with adding WebSockets[0] support to Guile's HTTP
arsenal. The first blocking issue I've come across is that an HTTP
server must be able to detect the "Upgrade" header[1] and change
protocols. In my case, once a client thread accepts a WebSocket
connection, it should speak the WebSocket protocol, not HTTP.
Here's an example of a backtrace that you'd see after a successful
WebSocket handshake, when the client tries to actually make use of the
socket:
In ice-9/boot-9.scm:
171:12 3 (with-throw-handler #t #<procedure 1720560 at web/...> #)
In web/server/http.scm:
126:17 2 (#<procedure 1720560 at web/server/http.scm:125:15 ()>)
In web/request.scm:
204:31 1 (read-request #<closed: file 0> ())
In ice-9/boot-9.scm:
106:20 0 (#<procedure 10ce380 at ice-9/boot-9.scm:97:6 (thr...> ...)
ERROR: Bad request: Bad Request-Line: "\x81\x86B\x93�Q"
Does anyone have an idea about how to approach this problem?
Thanks in advance!
[0] http://www.websocket.org/
[1] http://en.wikipedia.org/wiki/HTTP/1.1_Upgrade_header
--
David Thompson
Web Developer - Free Software Foundation - http://fsf.org
GPG Key: 0FF1D807
Support the FSF: https://fsf.org/donate
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: Handling HTTP "Upgrade" requests
2015-02-21 23:00 Handling HTTP "Upgrade" requests David Thompson
@ 2015-02-25 5:05 ` Nala Ginrut
2015-02-25 16:23 ` Dave Thompson
2015-03-04 10:51 ` Ludovic Courtès
1 sibling, 1 reply; 7+ messages in thread
From: Nala Ginrut @ 2015-02-25 5:05 UTC (permalink / raw)
To: David Thompson; +Cc: guile-devel
Hi David!
IMHO, there's no HTTP header anymore once you've done handshake
successfully, but sending frame defined by WebSocket.
For this case, once handshake is successful, I think you have to spawn a
new server instance (or use callbacks, depends on your server
architecture design) rather than using Guile inner HTTP server to manage
this socket. Or it'll be cracked while parsing HTTP header as you
pasted.
One of the possible way is to build a WebSocket gateway to dispatch the
connections to each server instance (or callbacks) and managing
handshake for each connection.
Anyway, to support WebSocket, one have to customize the server core. The
Guile inner server is dedicated to be the HTTP one, IIRC. That's why I
stopped development of websocket module in Artanis, since I have to
write its new async server core first. ;-)
On Sat, 2015-02-21 at 18:00 -0500, David Thompson wrote:
> I've been tinkering with adding WebSockets[0] support to Guile's HTTP
> arsenal. The first blocking issue I've come across is that an HTTP
> server must be able to detect the "Upgrade" header[1] and change
> protocols. In my case, once a client thread accepts a WebSocket
> connection, it should speak the WebSocket protocol, not HTTP.
>
> Here's an example of a backtrace that you'd see after a successful
> WebSocket handshake, when the client tries to actually make use of the
> socket:
>
> In ice-9/boot-9.scm:
> 171:12 3 (with-throw-handler #t #<procedure 1720560 at web/...> #)
> In web/server/http.scm:
> 126:17 2 (#<procedure 1720560 at web/server/http.scm:125:15 ()>)
> In web/request.scm:
> 204:31 1 (read-request #<closed: file 0> ())
> In ice-9/boot-9.scm:
> 106:20 0 (#<procedure 10ce380 at ice-9/boot-9.scm:97:6 (thr...> ...)
> ERROR: Bad request: Bad Request-Line: "\x81\x86B\x93�Q"
>
> Does anyone have an idea about how to approach this problem?
>
> Thanks in advance!
>
> [0] http://www.websocket.org/
> [1] http://en.wikipedia.org/wiki/HTTP/1.1_Upgrade_header
>
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: Handling HTTP "Upgrade" requests
2015-02-25 5:05 ` Nala Ginrut
@ 2015-02-25 16:23 ` Dave Thompson
2015-02-26 7:51 ` Nala Ginrut
0 siblings, 1 reply; 7+ messages in thread
From: Dave Thompson @ 2015-02-25 16:23 UTC (permalink / raw)
To: Nala Ginrut, David Thompson; +Cc: guile-devel
Nala Ginrut <nalaginrut@gmail.com> writes:
> Hi David!
>
> IMHO, there's no HTTP header anymore once you've done handshake
> successfully, but sending frame defined by WebSocket.
Yes, that is true.
> For this case, once handshake is successful, I think you have to spawn a
> new server instance (or use callbacks, depends on your server
> architecture design) rather than using Guile inner HTTP server to manage
> this socket. Or it'll be cracked while parsing HTTP header as you
> pasted.
>
> One of the possible way is to build a WebSocket gateway to dispatch the
> connections to each server instance (or callbacks) and managing
> handshake for each connection.
>
> Anyway, to support WebSocket, one have to customize the server core. The
> Guile inner server is dedicated to be the HTTP one, IIRC. That's why I
> stopped development of websocket module in Artanis, since I have to
> write its new async server core first. ;-)
IMO, an asynchronous/multi-threaded server is a separate issue. I was
aiming for a solution that allowed a single websocket to be used on
Guile's single-thread default web server. Of course, the websocket
implementation should be able to be applied to a more advanced server,
should one be written.
I think you're right that something in the default HTTP server must be
changed, but I haven't grokked the implementation enough to figure it
out. AFAICT, the HTTP server socket needs to be handed over to a
WebSocket server procedure, suspending additional HTTP request
processing until the WebSocket is closed and the socket is handed back
to the HTTP server. Does that make some sense? Things are too foggy
for me to tell.
--
David Thompson
Web Developer - Free Software Foundation - http://fsf.org
GPG Key: 0FF1D807
Support the FSF: https://fsf.org/donate
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: Handling HTTP "Upgrade" requests
2015-02-25 16:23 ` Dave Thompson
@ 2015-02-26 7:51 ` Nala Ginrut
2015-03-10 20:59 ` Andy Wingo
0 siblings, 1 reply; 7+ messages in thread
From: Nala Ginrut @ 2015-02-26 7:51 UTC (permalink / raw)
To: Dave Thompson; +Cc: guile-devel, David Thompson
On Wed, 2015-02-25 at 11:23 -0500, Dave Thompson wrote:
> IMO, an asynchronous/multi-threaded server is a separate issue. I was
> aiming for a solution that allowed a single websocket to be used on
> Guile's single-thread default web server. Of course, the websocket
> implementation should be able to be applied to a more advanced server,
> should one be written.
>
Ah I see.
> I think you're right that something in the default HTTP server must be
> changed, but I haven't grokked the implementation enough to figure it
> out. AFAICT, the HTTP server socket needs to be handed over to a
> WebSocket server procedure, suspending additional HTTP request
> processing until the WebSocket is closed and the socket is handed back
> to the HTTP server. Does that make some sense? Things are too foggy
> for me to tell.
Personally, I don't think websocket part should be based on inner HTTP
server. Or there'd be some changes of the architecture.
But if you really want to use inner server, I think there're some points
to be noticed:
1. check if it's websocket frame, then call the registered handler and
skip read-request to avoid the problem you've pasted;
2. the current inner server detects keep-alive based on HTTP header, so
you have to modify something to support comet connection for websocket
ports.
3. I have to mention that the current inner server is not non-block and
weak for slow-header-DDOS. So if you handle one request in a long time,
others' requests will be blocked in a long time. One of the easy
solution is to take advantage of Nginx reverse-proxy. But it doesn't
solve all the issues. ;-P
PS: To those who care, unfortunately, Guile has no epoll/kqueue yet,
that's one of the reasons why I want to write new server core for
Artanis. ;-)
Happy hacking!
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: Handling HTTP "Upgrade" requests
2015-02-21 23:00 Handling HTTP "Upgrade" requests David Thompson
2015-02-25 5:05 ` Nala Ginrut
@ 2015-03-04 10:51 ` Ludovic Courtès
1 sibling, 0 replies; 7+ messages in thread
From: Ludovic Courtès @ 2015-03-04 10:51 UTC (permalink / raw)
To: David Thompson; +Cc: guile-devel
David Thompson <davet@gnu.org> skribis:
> I've been tinkering with adding WebSockets[0] support to Guile's HTTP
> arsenal. The first blocking issue I've come across is that an HTTP
> server must be able to detect the "Upgrade" header[1] and change
> protocols. In my case, once a client thread accepts a WebSocket
> connection, it should speak the WebSocket protocol, not HTTP.
Roughly, I would change ‘http-write’ in (web server http) to just remove
the socket from the server’s poll set when the response is an upgrade, no?
Ludo’.
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: Handling HTTP "Upgrade" requests
2015-02-26 7:51 ` Nala Ginrut
@ 2015-03-10 20:59 ` Andy Wingo
2015-03-11 3:55 ` Nala Ginrut
0 siblings, 1 reply; 7+ messages in thread
From: Andy Wingo @ 2015-03-10 20:59 UTC (permalink / raw)
To: Nala Ginrut; +Cc: Dave Thompson, guile-devel, David Thompson
On Thu 26 Feb 2015 08:51, Nala Ginrut <nalaginrut@gmail.com> writes:
> 3. I have to mention that the current inner server is not non-block and
> weak for slow-header-DDOS.
Indeed. I think the right solution is cothreads. What do you think?
> PS: To those who care, unfortunately, Guile has no epoll/kqueue yet,
> that's one of the reasons why I want to write new server core for
> Artanis. ;-)
The wip-ethreads branch has something like this. Perhaps that could
serve for inspiration :)
Andy
--
http://wingolog.org/
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: Handling HTTP "Upgrade" requests
2015-03-10 20:59 ` Andy Wingo
@ 2015-03-11 3:55 ` Nala Ginrut
0 siblings, 0 replies; 7+ messages in thread
From: Nala Ginrut @ 2015-03-11 3:55 UTC (permalink / raw)
To: Andy Wingo; +Cc: Dave Thompson, guile-devel, David Thompson
On Tue, 2015-03-10 at 21:59 +0100, Andy Wingo wrote:
> On Thu 26 Feb 2015 08:51, Nala Ginrut <nalaginrut@gmail.com> writes:
>
> > 3. I have to mention that the current inner server is not non-block and
> > weak for slow-header-DDOS.
>
> Indeed. I think the right solution is cothreads. What do you think?
>
Yes, it's my answer too. ;-)
For more clearly, NIO + cooperative threads. If it's BIO, then it works
fine with normal/good requests, but halts with the intended tricky
formatted bad requests.
Sometimes it could halt long time when you upload bigger file. That's
what current Artanis suffering from. But could be solved easily with
Nginx reverse-proxy. Anyway, this issue is not only about NIO, there're
large room for optimizing though.
> > PS: To those who care, unfortunately, Guile has no epoll/kqueue yet,
> > that's one of the reasons why I want to write new server core for
> > Artanis. ;-)
>
> The wip-ethreads branch has something like this. Perhaps that could
> serve for inspiration :)
Yes, it's good start for me. Years ago, Mark once gave me a warn that a
good non-blocking design may need to change something in Guile-core,
especially ports. But it's not an easy work to make the whole Guile
support non-blocking in short time. Dunno if it's still true for current
Guile.
My plan is to provide restricted non-blocking I/O cautiously.
Of course, I'm optimistic to expect Guile support better non-blocking
from long term perspective. ;-)
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2015-03-11 3:55 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-02-21 23:00 Handling HTTP "Upgrade" requests David Thompson
2015-02-25 5:05 ` Nala Ginrut
2015-02-25 16:23 ` Dave Thompson
2015-02-26 7:51 ` Nala Ginrut
2015-03-10 20:59 ` Andy Wingo
2015-03-11 3:55 ` Nala Ginrut
2015-03-04 10:51 ` Ludovic Courtès
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).