-
Notifications
You must be signed in to change notification settings - Fork 44
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
A way to handle both websocket and regular HTTP requests #18
Comments
I'll think about it ASAP. |
I think we could do something like this: https://github.com/mirleft/ocaml-tls/blob/master/lwt/tls_lwt.mli When I wrote this code it was more with a client use-case in mind. But I agree that the server functionality is not very flexible as-is. I'll try to mimic the interface of Tls_lwt, soon. |
Thanks. No urgency ;) |
Any news about this ? |
On 09/10/2014 16:10, Zoggy wrote:
I started rewriting a websocket "decoder". I'll try to finish it asap. |
ping ! :) |
On 04/12/2014 16:53, Zoggy wrote:
Now that I did ocaml-scid, I master the non-blocking streaming technique Vincent |
I could use this as well -- happy to put in patches to Cohttp to support |
On 05/02/2015 11:54, Anil Madhavapeddy wrote:
Yeah, I definitely need to do this but fails to find the time for it. Vincent |
Here's my attempt at upgrade from cohttp: val upgrade_connection :
Cohttp.Request.t ->
Conduit_lwt_unix.flow * Cohttp.Connection.t ->
(Frame.t option -> unit) ->
(Cohttp.Response.t * Cohttp.Body.t * (Frame.t option -> unit)) Lwt.t
let upgrade_connection request (conn, conn_id) frames_in_fn =
let resp =
let headers = C.Request.headers request in
let key = Opt.run_exc @@ C.Header.get headers "sec-websocket-key" in
let hash = key ^ websocket_uuid |> b64_encoded_sha1sum in
let response_headers =
C.Header.of_list
["Upgrade", "websocket";
"Connection", "Upgrade";
"Sec-WebSocket-Accept", hash]
in
Cohttp_lwt_unix.Response.make
~status:`Switching_protocols
~encoding:Cohttp.Transfer.Unknown
~headers:response_headers
~flush:true
()
in
let frames_out_stream, frames_out_fn = Lwt_stream.create () in
Lwt.async (
fun () ->
let open Conduit_lwt_unix in
match conn with
| TCP (tcp : tcp_flow) ->
let ic = Lwt_io.make ~mode:Lwt_io.input (Lwt_bytes.read tcp.fd) in
let oc = Lwt_io.make ~mode:Lwt_io.output (Lwt_bytes.write tcp.fd) in
Lwt.join [
(* data in *)
read_frames (ic,oc) frames_in_fn frames_out_fn;
(* data out *)
send_frames ~masked:false frames_out_stream (ic,oc)
]
| _ -> Lwt.fail_with "expected a TCP Websocket connection"
);
Lwt.return (resp, Cohttp.Body.empty, frames_out_fn) And upgrading a | "/ws" ->
let print_frames = function
| None -> Printf.printf "None\n%!"
| Some f ->
match Websocket.Frame.content f with
| None -> Printf.printf "None\n%!"
| Some c -> Printf.printf "received: %s\n%!" c
in
Websocket.upgrade_connection req (ch, conn) print_frames
>>= fun (resp, body, frames_out_fn) ->
(* send a text frame back to the client every 5 seconds *)
let _ =
let rec go n =
Lwt_unix.sleep 5.0 >>= fun () ->
Lwt.wrap1
frames_out_fn
(Some (Websocket.Frame.of_string
~content:(Printf.sprintf "Ping! %d" n) ())) >>= fun () ->
if n > 0 then go (n-1) else Lwt.return_unit
in
go 1000
in
Lwt.return (resp, (body :> Cohttp_lwt_body.t)) Sadly, it doesn't work. Connection gets established but every 2nd frame I send to the server is somehow lost and after a while the connection just drops. Messages sent from the server to the client seem to fare a little better -- all of them get delivered. Any ideas why this fails? |
On 13/02/2015 03:51, Maciej Woś wrote:
I'll have a look perhaps. Do you answer pings ? Vincent |
I thought I don't have to do it explicitly. It looks like push_to_remote (Some (Frame.of_bytes ~opcode:Opcode.Pong ~extension ~final ~content ())); |
On 13/02/2015 10:42, Maciej Woś wrote:
Ah, right, yes. Vincent |
It seems something continues to read from the When I start another I came up with this hacky solution: let open Conduit_lwt_unix in
match conn with
| TCP (tcp : tcp_flow) ->
let dup = Lwt_unix.dup tcp.fd in
Lwt_unix.close tcp.fd >>= fun () ->
Cohttp_lwt_unix.Server.Response.write_header
resp
(Lwt_io.of_fd ~mode:Lwt_io.output dup)
>>= fun () ->
Lwt.join [
(* data in *)
read_frames
(Lwt_io.of_fd ~mode:Lwt_io.input dup)
frames_in_fn
frames_out_fn;
(* data out *)
send_frames
~masked:false (* server never masks the frames *)
frames_out_stream
(Lwt_io.of_fd ~mode:Lwt_io.output dup)
]
| _ -> Lwt.fail_with "expected a TCP Websocket connection" For what it's worth, it seems to work. I can establish the connection and send/receive frames. Note: I've changed my local version of Maybe |
Cohttp keeps reading in order to look for the next pipelined request. It could possibly stop reading if there were a Connection: close in the request.
|
We've been trying to figure this out as well, would love to figure something out here. |
@zoggy : Could you try this? Are you happy with this solution? |
Thanks. Looking at the exampe code in I can't give it a try right now but it seems ok to me. By the way, compilation still seems to require async to be installed:
|
@zoggy : Should we close this ticket? |
I did not find time yet to try, but |
Hello,
I'd like to build a server able to act as a regular HTTP server but also as a websocket server, depending on the path of the initial HTTP request. For example, querying http://myserver/ws will make a webserver connection, while querying any other path will make a regular HTTP connection (retrieving pages etc.).
I could not find a way to do so, the only function being available is establish_server. Could there be either a function to switch from a cohttp connection to a websocket connection, or either a parameter to establish_server allowing to stay in regular HTTP on a given condition ?
The text was updated successfully, but these errors were encountered: