]> Repositorios git - scryer-prolog.git/commitdiff
Request and Response headers
authorAdrián Arroyo Calle <[email protected]>
Sat, 12 Dec 2020 20:28:33 +0000 (21:28 +0100)
committerAdrián Arroyo Calle <[email protected]>
Sat, 12 Dec 2020 20:28:33 +0000 (21:28 +0100)
src/lib/http/http_server.pl

index c1889cff30df85dade653e3813a1cf8649ea77ce..486483c7d013cd024f6bfb9230fc2cdb18f9cc07 100644 (file)
@@ -1,4 +1,4 @@
-:- module(http_server, [http_listen/2, sample_handler/1]).
+:- module(http_server, [http_listen/2, sample_handler/2, sample_body_handler/2]).
 
 :- use_module(library(sockets)).
 :- use_module(library(dcgs)).
@@ -6,39 +6,51 @@
 :- use_module(library(error)).
 :- use_module(library(charsio)).
 :- use_module(library(lists)).
+:- use_module(library(iso_ext)).
 
 % TODO
-% - Parse request Headers
-% - Output response Headers
+% - Parse body
 % - Improve route matching
 % - Long-running socket_server_accept
 % - Cookies?
 % - HTTP Error Codes
 % - Redirections
 % - Improve code quality
+% - Binary
+% - Comments
 
 http_listen(Port, Handlers) :-
     must_be(integer, Port),
     must_be(list, Handlers),
     once(socket_server_open(Port, Socket)),
-    socket_server_accept(Socket, Client, Stream, [type(text)]),
+    socket_server_accept(Socket, Client, Stream, [type(binary)]),
     read_header_lines(Stream, Lines),
     [Request|Headers] = Lines,
+    % get_bytes(Stream, RequestBody), % Doesn't work
     (
-        phrase(parse_request(Version, Method, Path), Request) -> ( 
-                call_handler(Path, Headers, Handlers, Response),
-                http_response(StatusCode, Body) = Response,
-                format(Stream, "HTTP/1.0 ~d\r\n\r\n~s", [StatusCode, Body])
+        (phrase(parse_request(Version, Method, Path), Request), maplist(map_parse_header, Headers, HeadersKV)) -> ( 
+                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).
 
-call_handler(Path, Headers, Handlers, Response) :-
-    member(http_route(Dcg, Handler), Handlers),
+call_handler(Path, Headers, _, Handlers, Response) :-
+    member(get(Dcg, Handler), Handlers),
     phrase(Dcg, Path),!,
-    call(Handler, Response).
+    Request = http_request(Headers, _),
+    call(Handler, Request, Response).
+
+call_handler(Path, Headers, Body, Handlers, Response) :-
+    member(post(Dcg, Handler), Handlers),
+    phrase(Dcg, Path),!,
+    Request = http_request(Headers, Body),
+    call(Handler, Request, Response).
 
 call_handler(_, _, _, http_response(404, "Not found")).
 
@@ -53,6 +65,15 @@ parse_request(http_version(Major, Minor), Method, Path) -->
     natural(Minor),
     "\r\n".
 
+map_parse_header(Header, HeaderKV) :-
+    phrase(parse_header(HeaderKV), Header).
+
+parse_header(Key-Value) -->
+    string_without(":", Key),
+    ": ",
+    string_without("\r", Value),
+    "\r\n".
+
 method(options) --> "OPTIONS".
 method(get) --> "GET".
 method(head) --> "HEAD".
@@ -94,5 +115,16 @@ read_header_lines(Stream, Hs) :-
             read_header_lines(Stream, Rest)
         ).
 
-sample_handler(Response) :-
-    Response = http_response(200, "Hello Prolog friends!").
\ No newline at end of file
+
+get_bytes(Stream, Res) :- get_bytes(Stream, [], Res).
+get_bytes(Stream, Acc, Res) :-
+  get_byte(Stream, B),
+  (B =:= -1 ->
+    reverse(Acc, Res)
+  ; get_bytes(Stream, [B|Acc], Res)).
+
+sample_handler(http_request(Headers, _), Response) :-
+    member("User-Agent"-UserAgent, Headers),
+    Response = http_response(200, UserAgent, ["Content-Type"-"text/plain"]).
+
+sample_body_handler(http_request(Headers, Body), http_response(200, Body, ["Content-Type"-"application/json"])).
\ No newline at end of file