Read body
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
:- module(http_server, [http_listen/2, sample_handler/2, sample_body_handler/2]).
|
:- module(http_server, [http_listen/2, sample_handler/2, sample_body_handler/2, parse_request/5]).
|
||||||
|
|
||||||
:- use_module(library(sockets)).
|
:- use_module(library(sockets)).
|
||||||
:- use_module(library(dcgs)).
|
:- use_module(library(dcgs)).
|
||||||
@@ -18,27 +18,42 @@
|
|||||||
% - Improve code quality
|
% - Improve code quality
|
||||||
% - Binary
|
% - Binary
|
||||||
% - Comments
|
% - Comments
|
||||||
|
% - Test Suite
|
||||||
|
% - Keep-Alive
|
||||||
|
% - Case insensitive headers
|
||||||
|
|
||||||
http_listen(Port, Handlers) :-
|
http_listen(Port, Handlers) :-
|
||||||
must_be(integer, Port),
|
must_be(integer, Port),
|
||||||
must_be(list, Handlers),
|
must_be(list, Handlers),
|
||||||
once(socket_server_open(Port, Socket)),
|
once(socket_server_open(Port, Socket)),
|
||||||
socket_server_accept(Socket, Client, Stream, [type(binary)]),
|
format("Listening at port ~d\n", [Port]),
|
||||||
read_header_lines(Stream, Lines),
|
accept_loop(Socket, Handlers).
|
||||||
[Request|Headers] = Lines,
|
|
||||||
% get_bytes(Stream, RequestBody), % Doesn't work
|
accept_loop(Socket, Handlers) :-
|
||||||
(
|
setup_call_cleanup(socket_server_accept(Socket, Client, Stream, [type(binary)]),
|
||||||
(phrase(parse_request(Version, Method, Path), Request), maplist(map_parse_header, Headers, HeadersKV)) -> (
|
(
|
||||||
call_handler(Path, HeadersKV, RequestBody, Handlers, Response),
|
read_header_lines(Stream, Lines),
|
||||||
http_response(StatusCode, ResponseBody, RequestHeaders) = Response,
|
[Request|Headers] = Lines,
|
||||||
format(Stream, "HTTP/1.0 ~d\r\n", [StatusCode]),
|
(
|
||||||
forall(member(RequestHeaderKey-RequestHeaderValue, RequestHeaders), format(Stream, "~s: ~s\r\n", [RequestHeaderKey, RequestHeaderValue])),
|
(phrase(parse_request(Version, Method, Path), Request), maplist(map_parse_header, Headers, HeadersKV)) -> (
|
||||||
format(Stream, "\r\n~s", [ResponseBody])
|
(
|
||||||
);(
|
member("Content-Length"-ContentLength, HeadersKV) ->
|
||||||
format(Stream, "HTTP/1.0 400 Bad Request\r\n\r\n", []) % bad format
|
(number_chars(ContentLengthN, ContentLength), get_bytes(Stream, ContentLengthN, RequestBody))
|
||||||
)
|
;true
|
||||||
),
|
),
|
||||||
close(Stream).
|
format("~w ~s\n", [Method, Path]),
|
||||||
|
call_handler(Path, HeadersKV, RequestBody, Handlers, Response),
|
||||||
|
http_response(StatusCode, ResponseBody, RequestHeaders) = Response,
|
||||||
|
format(Stream, "HTTP/1.0 ~d\r\n", [StatusCode]),
|
||||||
|
forall(member(RequestHeaderKey-RequestHeaderValue, RequestHeaders), format(Stream, "~s: ~s\r\n", [RequestHeaderKey, RequestHeaderValue])),
|
||||||
|
format(Stream, "\r\n~s", [ResponseBody])
|
||||||
|
);(
|
||||||
|
format(Stream, "HTTP/1.0 400 Bad Request\r\n\r\n", []) % bad format
|
||||||
|
)
|
||||||
|
),
|
||||||
|
close(Stream)
|
||||||
|
), close(Stream)),
|
||||||
|
accept_loop(Socket, Handlers).
|
||||||
|
|
||||||
call_handler(Path, Headers, _, Handlers, Response) :-
|
call_handler(Path, Headers, _, Handlers, Response) :-
|
||||||
member(get(Dcg, Handler), Handlers),
|
member(get(Dcg, Handler), Handlers),
|
||||||
@@ -47,9 +62,10 @@ call_handler(Path, Headers, _, Handlers, Response) :-
|
|||||||
call(Handler, Request, Response).
|
call(Handler, Request, Response).
|
||||||
|
|
||||||
call_handler(Path, Headers, Body, Handlers, Response) :-
|
call_handler(Path, Headers, Body, Handlers, Response) :-
|
||||||
|
chars_utf8bytes(CharBody, Body),
|
||||||
member(post(Dcg, Handler), Handlers),
|
member(post(Dcg, Handler), Handlers),
|
||||||
phrase(Dcg, Path),!,
|
phrase(Dcg, Path),!,
|
||||||
Request = http_request(Headers, Body),
|
Request = http_request(Headers, CharBody),
|
||||||
call(Handler, Request, Response).
|
call(Handler, Request, Response).
|
||||||
|
|
||||||
call_handler(_, _, _, http_response(404, "Not found")).
|
call_handler(_, _, _, http_response(404, "Not found")).
|
||||||
@@ -115,16 +131,16 @@ read_header_lines(Stream, Hs) :-
|
|||||||
read_header_lines(Stream, Rest)
|
read_header_lines(Stream, Rest)
|
||||||
).
|
).
|
||||||
|
|
||||||
|
get_bytes(Stream, Length, Res) :- get_bytes(Stream, Length, [], Res).
|
||||||
get_bytes(Stream, Res) :- get_bytes(Stream, [], Res).
|
get_bytes(Stream, Length, Acc, Res) :-
|
||||||
get_bytes(Stream, Acc, Res) :-
|
(Length > 0 -> (
|
||||||
get_byte(Stream, B),
|
get_byte(Stream, B),
|
||||||
(B =:= -1 ->
|
B =\= -1,
|
||||||
reverse(Acc, Res)
|
get_bytes(Stream, Length - 1, [B|Acc], Res)
|
||||||
; get_bytes(Stream, [B|Acc], Res)).
|
); reverse(Acc, Res)).
|
||||||
|
|
||||||
sample_handler(http_request(Headers, _), Response) :-
|
sample_handler(http_request(Headers, _), Response) :-
|
||||||
member("User-Agent"-UserAgent, Headers),
|
member("User-Agent"-UserAgent, Headers),
|
||||||
Response = http_response(200, UserAgent, ["Content-Type"-"text/plain"]).
|
Response = http_response(200, UserAgent, ["Content-Type"-"text/plain", "Connection"-"Close"]).
|
||||||
|
|
||||||
sample_body_handler(http_request(Headers, Body), http_response(200, Body, ["Content-Type"-"application/json"])).
|
sample_body_handler(http_request(Headers, Body), http_response(200, Body, ["Content-Type"-"application/json"])).
|
||||||
Reference in New Issue
Block a user