77]).
88
99-define (PORT , 8080 ).
10+ -define (PORT_SSL , 8443 ).
11+ -define (LISTEN_OPTIONS , [
12+ binary ,
13+ {active , false },
14+ {backlog , 128 },
15+ {packet , http_bin },
16+ {reuseaddr , true }
17+ ]).
1018
1119% % public
1220connection_count () ->
@@ -35,74 +43,94 @@ stop() ->
3543init (Parent ) ->
3644 register (? MODULE , self ()),
3745 persistent_term :put ({? MODULE , connections }, counters :new (1 , [])),
38- {ok , LSocket } = gen_tcp :listen (? PORT , [
39- binary ,
40- {active , false },
41- {backlog , 128 },
42- {packet , http_bin },
43- {reuseaddr , true }
44- ]),
46+ {ok , _ } = application :ensure_all_started (ssl ),
47+ {ok , LSocket } = gen_tcp :listen (? PORT , ? LISTEN_OPTIONS ),
48+ % % the default pkix_test_data key (secp112r2, sha1) is not
49+ % % negotiable by a modern TLS client
50+ KeyOpts = [{key , {namedCurve , secp256r1 }}, {digest , sha256 }],
51+ SslOptions = public_key :pkix_test_data (#{root => KeyOpts ,
52+ peer => KeyOpts }),
53+ {ok , LSocketSsl } = ssl :listen (? PORT_SSL , ? LISTEN_OPTIONS ++ SslOptions ),
54+ spawn_link (fun () -> accept_ssl (LSocketSsl ) end ),
4555 Parent ! {self (), started },
4656 accept (LSocket ).
4757
4858accept (LSocket ) ->
4959 {ok , Socket } = gen_tcp :accept (LSocket ),
5060 counters :add (persistent_term :get ({? MODULE , connections }), 1 , 1 ),
5161 Pid = spawn_link (fun () ->
52- receive go -> connection (Socket ) end
62+ receive go -> connection (gen_tcp , Socket ) end
5363 end ),
5464 ok = gen_tcp :controlling_process (Socket , Pid ),
5565 Pid ! go ,
5666 accept (LSocket ).
5767
58- connection (Socket ) ->
59- case gen_tcp :recv (Socket , 0 ) of
68+ accept_ssl (LSocket ) ->
69+ {ok , TSocket } = ssl :transport_accept (LSocket ),
70+ counters :add (persistent_term :get ({? MODULE , connections }), 1 , 1 ),
71+ Pid = spawn_link (fun () ->
72+ receive
73+ go ->
74+ case ssl :handshake (TSocket ) of
75+ {ok , Socket } ->
76+ connection (ssl , Socket );
77+ {error , _ } ->
78+ ok
79+ end
80+ end
81+ end ),
82+ ok = ssl :controlling_process (TSocket , Pid ),
83+ Pid ! go ,
84+ accept_ssl (LSocket ).
85+
86+ connection (Transport , Socket ) ->
87+ case recv (Transport , Socket , 0 ) of
6088 {ok , {http_request , Method , {abs_path , Path }, _Version }} ->
61- ContentLength = headers (Socket , 0 ),
62- Body = body (Socket , ContentLength ),
63- respond (Socket , Method , Path , Body ),
64- connection (Socket );
89+ ContentLength = headers (Transport , Socket , 0 ),
90+ Body = body (Transport , Socket , ContentLength ),
91+ respond (Transport , Socket , Method , Path , Body ),
92+ connection (Transport , Socket );
6593 {ok , _ } ->
66- gen_tcp : close (Socket );
94+ close (Transport , Socket );
6795 {error , _ } ->
68- gen_tcp : close (Socket )
96+ close (Transport , Socket )
6997 end .
7098
71- headers (Socket , ContentLength ) ->
72- case gen_tcp : recv (Socket , 0 ) of
99+ headers (Transport , Socket , ContentLength ) ->
100+ case recv (Transport , Socket , 0 ) of
73101 {ok , {http_header , _ , 'Content-Length' , _ , Value }} ->
74- headers (Socket , binary_to_integer (Value ));
102+ headers (Transport , Socket , binary_to_integer (Value ));
75103 {ok , {http_header , _ , _ , _ , _ }} ->
76- headers (Socket , ContentLength );
104+ headers (Transport , Socket , ContentLength );
77105 {ok , http_eoh } ->
78106 ContentLength
79107 end .
80108
81- body (_Socket , 0 ) ->
109+ body (_Transport , _Socket , 0 ) ->
82110 <<>>;
83- body (Socket , ContentLength ) ->
84- ok = inet : setopts (Socket , [{packet , raw }]),
85- {ok , Body } = gen_tcp : recv (Socket , ContentLength ),
86- ok = inet : setopts (Socket , [{packet , http_bin }]),
111+ body (Transport , Socket , ContentLength ) ->
112+ ok = setopts (Transport , Socket , [{packet , raw }]),
113+ {ok , Body } = recv (Transport , Socket , ContentLength ),
114+ ok = setopts (Transport , Socket , [{packet , http_bin }]),
87115 Body .
88116
89- respond (Socket , Method , <<" /1" >>, _Body ) ->
90- reply (Socket , Method , <<" Hello world!" >>);
91- respond (Socket , Method , <<" /2" >>, _Body ) ->
92- reply (Socket , Method , binary :copy (<<" Hello world!" >>, 1000 ));
93- respond (Socket , Method , <<" /3" >>, Body ) ->
94- reply (Socket , Method , Body );
95- respond (Socket , Method , <<" /4" >>, _Body ) ->
96- chunked_reply (Socket , Method , [<<" Hello" >>, <<" world!" >>]);
97- respond (Socket , Method , <<" /5" >>, _Body ) ->
98- reply (Socket , Method , method (Method )).
117+ respond (Transport , Socket , Method , <<" /1" >>, _Body ) ->
118+ reply (Transport , Socket , Method , <<" Hello world!" >>);
119+ respond (Transport , Socket , Method , <<" /2" >>, _Body ) ->
120+ reply (Transport , Socket , Method , binary :copy (<<" Hello world!" >>, 1000 ));
121+ respond (Transport , Socket , Method , <<" /3" >>, Body ) ->
122+ reply (Transport , Socket , Method , Body );
123+ respond (Transport , Socket , Method , <<" /4" >>, _Body ) ->
124+ chunked_reply (Transport , Socket , Method , [<<" Hello" >>, <<" world!" >>]);
125+ respond (Transport , Socket , Method , <<" /5" >>, _Body ) ->
126+ reply (Transport , Socket , Method , method (Method )).
99127
100128method (Method ) when is_atom (Method ) ->
101129 atom_to_binary (Method , utf8 );
102130method (Method ) when is_binary (Method ) ->
103131 Method .
104132
105- reply (Socket , Method , Body ) ->
133+ reply (Transport , Socket , Method , Body ) ->
106134 Headers = [
107135 <<" HTTP/1.1 200 OK\r\n " >>,
108136 <<" Connection: Keep-Alive\r\n " >>,
@@ -112,12 +140,12 @@ reply(Socket, Method, Body) ->
112140 ],
113141 case Method of
114142 'HEAD' ->
115- ok = gen_tcp : send (Socket , Headers );
143+ ok = send (Transport , Socket , Headers );
116144 _ ->
117- ok = gen_tcp : send (Socket , [Headers , Body ])
145+ ok = send (Transport , Socket , [Headers , Body ])
118146 end .
119147
120- chunked_reply (Socket , Method , Chunks ) ->
148+ chunked_reply (Transport , Socket , Method , Chunks ) ->
121149 Headers = [
122150 <<" HTTP/1.1 200 OK\r\n " >>,
123151 <<" Connection: Keep-Alive\r\n " >>,
@@ -126,9 +154,29 @@ chunked_reply(Socket, Method, Chunks) ->
126154 ],
127155 case Method of
128156 'HEAD' ->
129- ok = gen_tcp : send (Socket , Headers );
157+ ok = send (Transport , Socket , Headers );
130158 _ ->
131159 Encoded = [[integer_to_binary (byte_size (Chunk ), 16 ), <<" \r\n " >>,
132160 Chunk , <<" \r\n " >>] || Chunk <- Chunks ],
133- ok = gen_tcp : send (Socket , [Headers , Encoded , <<" 0\r\n\r\n " >>])
161+ ok = send (Transport , Socket , [Headers , Encoded , <<" 0\r\n\r\n " >>])
134162 end .
163+
164+ close (gen_tcp , Socket ) ->
165+ gen_tcp :close (Socket );
166+ close (ssl , Socket ) ->
167+ ssl :close (Socket ).
168+
169+ recv (gen_tcp , Socket , Length ) ->
170+ gen_tcp :recv (Socket , Length );
171+ recv (ssl , Socket , Length ) ->
172+ ssl :recv (Socket , Length ).
173+
174+ send (gen_tcp , Socket , Data ) ->
175+ gen_tcp :send (Socket , Data );
176+ send (ssl , Socket , Data ) ->
177+ ssl :send (Socket , Data ).
178+
179+ setopts (gen_tcp , Socket , Opts ) ->
180+ inet :setopts (Socket , Opts );
181+ setopts (ssl , Socket , Opts ) ->
182+ ssl :setopts (Socket , Opts ).
0 commit comments