From 155004bdbbbbee6a455af29664b1ee97b8d7b2ac Mon Sep 17 00:00:00 2001 From: =?utf8?q?Adri=C3=A1n=20Arroyo=20Calle?= Date: Sun, 27 Dec 2020 22:36:24 +0100 Subject: [PATCH] Log time --- src/lib/http/http_server.pl | 76 +++++++++++++++++++------------------ 1 file changed, 39 insertions(+), 37 deletions(-) diff --git a/src/lib/http/http_server.pl b/src/lib/http/http_server.pl index 33074460..fb76dea4 100644 --- a/src/lib/http/http_server.pl +++ b/src/lib/http/http_server.pl @@ -41,6 +41,8 @@ - Read forms - HTTP Basic Auth - Keep-Alive support + - Session handling via cookies + - HTML Templating I place this code in the public domain. Use it in any way you want. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ @@ -51,8 +53,7 @@ http_status_code/2, http_body/2, http_redirect/2, - http_query/3, - path//1 + http_query/3 ]). :- use_module(library(sockets)). @@ -62,22 +63,20 @@ :- use_module(library(charsio)). :- use_module(library(lists)). :- use_module(library(iso_ext)). +:- use_module(library(time)). % TODO -% - Cookies? % - HTTP Error Codes % - Improve code quality % - Comments -% - Keep-Alive -% - Case insensitive headers -% - HTML % - Remove ! % - URL Encode -% - Forms -% - HTTP Auth +% The route matching system needs a dynamic predicate to re-use the vars +% defined in the patterns :- dynamic(http_handler/3). +% Server initialization http_listen(Port, Handlers) :- must_be(integer, Port), must_be(list, Handlers), @@ -86,29 +85,14 @@ http_listen(Port, Handlers) :- format("Listening at port ~d\n", [Port]), accept_loop(Socket). +% Register handlers register_handlers([]). -register_handlers([get(Path, Handler)|Handlers]) :- - asserta(http_handler(get, Path, Handler)), - register_handlers(Handlers). -register_handlers([post(Path, Handler)|Handlers]) :- - asserta(http_handler(post, Path, Handler)), - register_handlers(Handlers). -register_handlers([put(Path, Handler)|Handlers]) :- - asserta(http_handler(put, Path, Handler)), - register_handlers(Handlers). -register_handlers([patch(Path, Handler)|Handlers]) :- - asserta(http_handler(patch, Path, Handler)), - register_handlers(Handlers). -register_handlers([head(Path, Handler)|Handlers]) :- - asserta(http_handler(head, Path, Handler)), - register_handlers(Handlers). -register_handlers([delete(Path, Handler)|Handlers]) :- - asserta(http_handler(delete, Path, Handler)), - register_handlers(Handlers). -register_handlers([options(Path, Handler)|Handlers]) :- - asserta(http_handler(options, Path, Handler)), +register_handlers([Handler|Handlers]) :- + Handler =.. [Method, Path, Closure], + asserta(http_handler(Method, Path, Closure)), register_handlers(Handlers). +% Server loop accept_loop(Socket) :- setup_call_cleanup(socket_server_accept(Socket, Client, Stream, [type(binary)]), ( @@ -117,11 +101,13 @@ accept_loop(Socket) :- ( (phrase(parse_request(Version, Method, Path, Queries), Request), maplist(map_parse_header, Headers, HeadersKV)) -> ( ( - member("Content-Length"-ContentLength, HeadersKV) -> + member("content-length"-ContentLength, HeadersKV) -> (number_chars(ContentLengthN, ContentLength), get_bytes(Stream, ContentLengthN, Body)) ;true ), - format("~w ~s\n", [Method, Path]), + current_time(Time), + phrase(format_time("%Y-%m-%d (%H:%M:%S)", Time), TimeString), + format("~s ~w ~s\n", [TimeString, Method, Path]), ( (http_handler(Method, Pattern, Handler), phrase(path(Pattern), Path)) -> ( @@ -144,7 +130,6 @@ accept_loop(Socket) :- % Helper and recommended predicates -% http_header(Response, HEaderName, Value) http_headers(http_request(Headers, _, _), Headers). http_headers(http_response(_, _, Headers), Headers). @@ -158,6 +143,7 @@ http_redirect(http_response(307, text("Moved Temporarily"), ["Location"-Uri]), U http_query(http_request(_, _, Queries), Key, Value) :- member(Key-Value, Queries). +% Route matching path(Pattern) --> { Pattern =.. Parts, @@ -181,11 +167,12 @@ path(Pattern) --> path([]) --> []. +% Send responses send_response(Stream, http_response(StatusCode0, file(Filename), Headers)) :- default(StatusCode0, 200, StatusCode), format(Stream, "HTTP/1.0 ~d\r\n", [StatusCode]), - overwrite_header("Connection"-"Close", Headers0, Headers1), - write_headers(Stream, Headers1), + overwrite_header("connection"-"Close", Headers, Headers0), + write_headers(Stream, Headers0), format(Stream, "\r\n", []), setup_call_cleanup( open(Filename, read, FileStream, [type(binary)]), @@ -196,15 +183,15 @@ send_response(Stream, http_response(StatusCode0, file(Filename), Headers)) :- send_response(Stream, http_response(StatusCode0, text(TextResponse), Headers)) :- default(StatusCode0, 200, StatusCode), format(Stream, "HTTP/1.0 ~d\r\n", [StatusCode]), - overwrite_header("Content-Type"-"text/plain", Headers, Headers0), - overwrite_header("Connection"-"Close", Headers0, Headers1), + 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(StatusCode0, binary(BinaryResponse), Headers)) :- default(StatusCode0, 200, StatusCode), format(Stream, "HTTP/1.0 ~d\r\n", [StatusCode]), - overwrite_header("Connection"-"Close", Headers, Headers0), + overwrite_header("connection"-"Close", Headers, Headers0), write_headers(Stream, Headers0), format(Stream, "\r\n", []), put_bytes(Stream, BinaryResponse). @@ -267,7 +254,10 @@ map_parse_header(Header, HeaderKV) :- phrase(parse_header(HeaderKV), Header). parse_header(Key-Value) --> - string_without(":", Key), + string_without(":", Key0), + { + chars_lower(Key0, Key) + }, ": ", string_without("\r", Value), "\r\n". @@ -335,3 +325,15 @@ pipe_bytes(StreamIn, StreamOut) :- pipe_bytes(StreamIn, StreamOut) ) ; true). + +% WARNING: This only works for ASCII chars. This code can be modified to support +% Latin1 characters also but a completely different approach is needed for other +% languages. Since HTTP internals are ASCII, this is fine for this usecase. +chars_lower(Chars, Lower) :- + maplist(char_lower, Chars, Lower). +char_lower(Char, Lower) :- + char_code(Char, Code), + ((Code >= 65,Code =< 90) -> + LowerCode is Code + 32, + char_code(Lower, LowerCode) + ; Char = Lower). -- 2.54.0