HTTP Body

This commit is contained in:
Adrián Arroyo Calle
2020-12-21 00:15:00 +01:00
parent 33a0df20c3
commit e1f4a50e65

View File

@@ -1,4 +1,4 @@
:- module(http_server, [http_listen/2, sample_handler/2, sample_body_handler/2, parse_request/5]). :- module(http_server, [http_listen/2]).
:- use_module(library(sockets)). :- use_module(library(sockets)).
:- use_module(library(dcgs)). :- use_module(library(dcgs)).
@@ -42,16 +42,15 @@ accept_loop(Socket, Handlers) :-
;true ;true
), ),
format("~w ~s\n", [Method, Path]), format("~w ~s\n", [Method, Path]),
call_handler(Path, HeadersKV, RequestBody, Handlers, Response), ( call_handler(Path, HeadersKV, RequestBody, Handlers, Response) ->
http_response(StatusCode, ResponseBody, RequestHeaders) = Response, send_response(Stream, Response)
format(Stream, "HTTP/1.0 ~d\r\n", [StatusCode]), ; format(Stream, "HTTP/1.0 500 Internal Server Error\r\n\r\n", [])
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 format(Stream, "HTTP/1.0 400 Bad Request\r\n\r\n", []) % bad format
) )
), ),
close(Stream) ! % Remove
), close(Stream)), ), close(Stream)),
accept_loop(Socket, Handlers). accept_loop(Socket, Handlers).
@@ -62,14 +61,44 @@ 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, CharBody), build_response(Body, ResponseBody),
Request = http_request(Headers, ResponseBody),
call(Handler, Request, Response). call(Handler, Request, Response).
call_handler(_, _, _, http_response(404, "Not found")). call_handler(_, _, _, http_response(404, "Not found")).
build_response(ByteBody, text(TextBody)) :-
chars_utf8bytes(TextBody, ByteBody).
build_response(ByteBody, binary(ByteBody)).
send_response(Stream, http_response(StatusCode, text(TextResponse), Headers)) :-
format(Stream, "HTTP/1.0 ~d\r\n", [StatusCode]),
overwrite_header("Content-Type"-"text/plain", Headers, Headers0),
overwrite_header("Connection"-"Close", Headers0, Headers1),
write_headers(Stream, Headers1),
format(Stream, "\r\n~s", [TextResponse]).
send_response(Stream, http_response(StatusCode, binary(BinaryResponse), Headers)) :-
format(Stream, "HTTP/1.0 ~d\r\n", [StatusCode]),
overwrite_header("Connection"-"Close", Headers, Headers0),
write_headers(Stream, Headers0),
format(Stream, "\r\n", []),
put_bytes(Stream, BinaryResponse).
write_headers(Stream, Headers) :-
forall(member(Key-Value, Headers), format(Stream, "~s: ~s\r\n", [Key, Value])).
overwrite_header(Key-Value, [], [Key-Value]).
overwrite_header(Key-Value, [Header|Headers], HeadersOut) :-
Header = Key0-_,
Key0 \= Key,
overwrite_header(Key-Value, Headers, HeadersOut).
overwrite_header(Key-Value, [Header|Headers], [NewHeader|Headers]) :-
Header = Key-_,
NewHeader = Key-Value.
parse_request(http_version(Major, Minor), Method, Path) --> parse_request(http_version(Major, Minor), Method, Path) -->
method(Method), method(Method),
" ", " ",
@@ -139,8 +168,7 @@ get_bytes(Stream, Length, Acc, Res) :-
get_bytes(Stream, Length - 1, [B|Acc], Res) get_bytes(Stream, Length - 1, [B|Acc], Res)
); reverse(Acc, Res)). ); reverse(Acc, Res)).
sample_handler(http_request(Headers, _), Response) :- put_bytes(_, []).
member("User-Agent"-UserAgent, Headers), put_bytes(Stream, [Byte|Bytes]) :-
Response = http_response(200, UserAgent, ["Content-Type"-"text/plain", "Connection"-"Close"]). put_byte(Stream, Byte),
put_bytes(Stream, Bytes).
sample_body_handler(http_request(Headers, Body), http_response(200, Body, ["Content-Type"-"application/json"])).