/modules/mod_base/resources/resource_websocket.erl

https://code.google.com/p/zotonic/ · Erlang · 111 lines · 67 code · 18 blank · 26 comment · 0 complexity · 3ffe8c2e3660e3a4e1af444d7373bcdd MD5 · raw file

  1. %% @author Marc Worrell <marc@worrell.nl>
  2. %% @copyright 2010 Marc Worrell
  3. %% @doc WebSocket connections
  4. %% Copyright 2010 Marc Worrell
  5. %%
  6. %% Licensed under the Apache License, Version 2.0 (the "License");
  7. %% you may not use this file except in compliance with the License.
  8. %% You may obtain a copy of the License at
  9. %%
  10. %% http://www.apache.org/licenses/LICENSE-2.0
  11. %%
  12. %% Unless required by applicable law or agreed to in writing, software
  13. %% distributed under the License is distributed on an "AS IS" BASIS,
  14. %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. %% See the License for the specific language governing permissions and
  16. %% limitations under the License.
  17. -module(resource_websocket).
  18. -author("Marc Worrell <marc@worrell.nl>").
  19. -export([
  20. init/1,
  21. forbidden/2,
  22. upgrades_provided/2,
  23. charsets_provided/2,
  24. content_types_provided/2,
  25. provide_content/2,
  26. websocket_start/2,
  27. handle_message/2
  28. ]).
  29. -include_lib("webmachine_resource.hrl").
  30. -include_lib("include/zotonic.hrl").
  31. init(_Args) -> {ok, []}.
  32. %% @doc The request must have a valid session cookie.
  33. forbidden(ReqData, _State) ->
  34. Context = z_context:new(ReqData),
  35. Context1 = z_context:continue_session(Context),
  36. ?WM_REPLY(not z_context:has_session(Context1), Context1).
  37. %% @doc Possible connection upgrades
  38. upgrades_provided(ReqData, Context) ->
  39. {[
  40. {"WebSocket", websocket_start}
  41. ], ReqData, Context}.
  42. charsets_provided(ReqData, Context) ->
  43. {[{"utf-8", fun(X) -> X end}], ReqData, Context}.
  44. content_types_provided(ReqData, Context) ->
  45. {[{"text/html", provide_content}], ReqData, Context}.
  46. provide_content(ReqData, Context) ->
  47. Context1 = ?WM_REQ(ReqData, Context),
  48. Context2 = z_context:ensure_qs(Context1),
  49. Context3 = z_context:set_resp_header("X-Robots-Tag", "noindex", Context2),
  50. Rendered = z_template:render("error_websocket.tpl", z_context:get_all(Context), Context3),
  51. {Output, OutputContext} = z_context:output(Rendered, Context3),
  52. ?WM_REPLY(Output, OutputContext).
  53. %% @doc Initiate the websocket connection upgrade
  54. websocket_start(ReqData, Context) ->
  55. ContextReq = ?WM_REQ(ReqData, Context),
  56. Context1 = z_context:ensure_all(ContextReq),
  57. case z_context:get_req_header("sec-websocket-version", Context1) of
  58. undefined ->
  59. case z_context:get_req_header("sec-websocket-key1", Context1) of
  60. undefined ->
  61. z_websocket_hixie75:start(ReqData, Context1);
  62. WsKey1 ->
  63. z_websocket_hybi00:start(WsKey1, ReqData, Context1)
  64. end;
  65. % https://github.com/ostinelli/misultin/commit/23b21e0c8d1d9aa4bc0ce60d527a8716d76e025c
  66. "7" ->
  67. % http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-07
  68. todo; % hybi07(WsKey1, Context1);
  69. "8" ->
  70. % http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-10
  71. todo % hybi10(WsKey1, Context1)
  72. end.
  73. %% Handle a message from the browser, should contain an url encoded request. Sends result script back to browser.
  74. handle_message(Msg, Context) ->
  75. Qs = mochiweb_util:parse_qs(Msg),
  76. Context1 = z_context:set('q', Qs, Context),
  77. {ResultScript, ResultContext} = try
  78. % Enable caching lookup values, essential for fast data handling
  79. z_depcache:in_process(true),
  80. resource_postback:process_postback(Context1)
  81. catch
  82. Error:X ->
  83. ?zWarning(io_lib:format("~p:~p~n~p", [Error, X, erlang:get_stacktrace()]), Context1),
  84. {case z_context:get_q("z_trigger_id", Context1) of
  85. undefined -> [];
  86. ZTrigger -> [" z_unmask_error('",z_utils:js_escape(ZTrigger),"');"]
  87. end,
  88. Context1}
  89. end,
  90. % Cleanup process dict, so our process heap is smaller between calls
  91. % z_depcache:flush_process_dict(),
  92. z_session_page:add_script(ResultScript, ResultContext),
  93. erlang:erase().