Skip to content

Commit

Permalink
Allow custom paths to be provided to :websocket and :longpoll (phoeni…
Browse files Browse the repository at this point in the history
…xframework#3166)

* Allow custom paths to be provided to :websocket and :longpoll

Previously, it was not possible to use a socket with a path that differed from
the key name. For example `:websocket` would always end with `/websocket` and
`:longpoll` would always end with `/longpoll`.

This commit allows a `:path` to be passed into the keyword options, the path
will be used instead of the default if available.
  • Loading branch information
Gazler authored Nov 16, 2018
1 parent 560fde8 commit 8724479
Show file tree
Hide file tree
Showing 5 changed files with 32 additions and 13 deletions.
18 changes: 12 additions & 6 deletions lib/phoenix/endpoint.ex
Original file line number Diff line number Diff line change
Expand Up @@ -777,25 +777,28 @@ defmodule Phoenix.Endpoint do

paths =
if websocket do
triplet = {:websocket, socket, socket_config(websocket, Phoenix.Transports.WebSocket)}
[{socket_path(path, :websocket), triplet} | paths]
config = socket_config(websocket, Phoenix.Transports.WebSocket)
triplet = {:websocket, socket, config}
[{socket_path(path, config), triplet} | paths]
else
paths
end

paths =
if longpoll do
plug_init = {endpoint, socket, socket_config(longpoll, Phoenix.Transports.LongPoll)}
[{socket_path(path, :longpoll), {:plug, Phoenix.Transports.LongPoll, plug_init}} | paths]
config = socket_config(longpoll, Phoenix.Transports.LongPoll)
plug_init = {endpoint, socket, config}
[{socket_path(path, config), {:plug, Phoenix.Transports.LongPoll, plug_init}} | paths]
else
paths
end

paths
end

defp socket_path(path, key) do
String.split(path, "/", trim: true) ++ [Atom.to_string(key)]
defp socket_path(path, config) do
end_path_fragment = Keyword.fetch!(config, :path)
String.split(path <> "/" <> end_path_fragment, "/", trim: true)
end

defp socket_config(true, module), do: module.default_config()
Expand Down Expand Up @@ -839,6 +842,9 @@ defmodule Phoenix.Endpoint do
The configuration below can be given to both `:websocket` and
`:longpoll` keys:
* `:path` - the path to use for the transport. Will default
to the transport name ("/websocket" or "/longpoll")
* `:serializer` - a list of serializers for messages. See
`Phoenix.Socket` for more information
Expand Down
16 changes: 9 additions & 7 deletions lib/phoenix/endpoint/cowboy_adapter.ex
Original file line number Diff line number Diff line change
Expand Up @@ -104,10 +104,11 @@ defmodule Phoenix.Endpoint.CowboyAdapter do

paths =
if websocket do
init = {endpoint, socket, socket_config(websocket, Phoenix.Transports.WebSocket)}
config = socket_config(websocket, Phoenix.Transports.WebSocket)
init = {endpoint, socket, config}

[
{socket_path(path, :websocket), Phoenix.Endpoint.CowboyWebSocket,
{socket_path(path, config), Phoenix.Endpoint.CowboyWebSocket,
{Phoenix.Transports.WebSocket, init}}
| paths
]
Expand All @@ -117,10 +118,11 @@ defmodule Phoenix.Endpoint.CowboyAdapter do

paths =
if longpoll do
init = {endpoint, socket, socket_config(longpoll, Phoenix.Transports.LongPoll)}
config = socket_config(longpoll, Phoenix.Transports.LongPoll)
init = {endpoint, socket, config}

[
{socket_path(path, :longpoll), Plug.Adapters.Cowboy.Handler,
{socket_path(path, config), Plug.Adapters.Cowboy.Handler,
{Phoenix.Transports.LongPoll, init}}
| paths
]
Expand All @@ -130,9 +132,9 @@ defmodule Phoenix.Endpoint.CowboyAdapter do

paths
end

defp socket_path(path, key) do
parts = String.split(path, "/", trim: true) ++ [Atom.to_string(key)]
defp socket_path(path, config) do
end_path_fragment = Keyword.fetch!(config, :path)
parts = String.split(path <> "/" <> end_path_fragment, "/", trim: true)
"/" <> Path.join(parts)
end

Expand Down
1 change: 1 addition & 0 deletions lib/phoenix/transports/long_poll.ex
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ defmodule Phoenix.Transports.LongPoll do
def default_config() do
[
window_ms: 10_000,
path: "/longpoll",
pubsub_timeout_ms: 2_000,
serializer: [{V1.JSONSerializer, "~> 1.0.0"}, {V2.JSONSerializer, "~> 2.0.0"}],
transport_log: false,
Expand Down
1 change: 1 addition & 0 deletions lib/phoenix/transports/websocket.ex
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ defmodule Phoenix.Transports.WebSocket do

def default_config() do
[
path: "/websocket",
serializer: [{V1.JSONSerializer, "~> 1.0.0"}, {V2.JSONSerializer, "~> 2.0.0"}],
timeout: 60_000,
transport_log: false,
Expand Down
9 changes: 9 additions & 0 deletions test/phoenix/integration/websocket_socket_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@ defmodule Phoenix.Integration.WebSocketTest do
socket "/ws", UserSocket,
websocket: [check_origin: ["//example.com"], timeout: 200],
custom: :value

socket "/custom/some_path", UserSocket,
websocket: [path: "nested/path", check_origin: ["//example.com"], timeout: 200],
custom: :value
end

setup_all do
Expand Down Expand Up @@ -91,4 +95,9 @@ defmodule Phoenix.Integration.WebSocketTest do
WebsocketClient.send_message(client, "ping")
assert_receive {:text, "pong"}
end

test "allows a custom path" do
path = "ws://127.0.0.1:#{@port}/custom/some_path/nested/path"
assert {:ok, client} = WebsocketClient.start_link(self(), "#{path}?key=value", :noop)
end
end

0 comments on commit 8724479

Please sign in to comment.