]> Repositorios git - scryer-prolog.git/commitdiff
Read body
authorAdrián Arroyo Calle <[email protected]>
Mon, 14 Dec 2020 21:57:53 +0000 (22:57 +0100)
committerAdrián Arroyo Calle <[email protected]>
Mon, 14 Dec 2020 21:57:53 +0000 (22:57 +0100)
src/lib/http/http_server.pl

index 486483c7d013cd024f6bfb9230fc2cdb18f9cc07..5eeb4847d1b80ba92f8347bc3fd06a5b298620cb 100644 (file)
@@ -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(dcgs)).
 % - Improve code quality
 % - Binary
 % - Comments
+% - Test Suite
+% - Keep-Alive
+% - Case insensitive headers
 
 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(binary)]),
-    read_header_lines(Stream, Lines),
-    [Request|Headers] = Lines,
-    % get_bytes(Stream, RequestBody), % Doesn't work
-    (
-        (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).
+    format("Listening at port ~d\n", [Port]),
+    accept_loop(Socket, Handlers).
+
+accept_loop(Socket, Handlers) :-
+    setup_call_cleanup(socket_server_accept(Socket, Client, Stream, [type(binary)]),
+        (
+            read_header_lines(Stream, Lines),
+            [Request|Headers] = Lines,
+            (
+                (phrase(parse_request(Version, Method, Path), Request), maplist(map_parse_header, Headers, HeadersKV)) -> (
+                        (
+                            member("Content-Length"-ContentLength, HeadersKV) ->
+                                (number_chars(ContentLengthN, ContentLength), get_bytes(Stream, ContentLengthN, RequestBody))
+                                ;true
+                        ),
+                        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) :-
     member(get(Dcg, Handler), Handlers),
@@ -47,9 +62,10 @@ call_handler(Path, Headers, _, Handlers, Response) :-
     call(Handler, Request, Response).
 
 call_handler(Path, Headers, Body, Handlers, Response) :-
+    chars_utf8bytes(CharBody, Body),
     member(post(Dcg, Handler), Handlers),
     phrase(Dcg, Path),!,
-    Request = http_request(Headers, Body),
+    Request = http_request(Headers, CharBody),
     call(Handler, Request, Response).
 
 call_handler(_, _, _, http_response(404, "Not found")).
@@ -115,16 +131,16 @@ read_header_lines(Stream, Hs) :-
             read_header_lines(Stream, Rest)
         ).
 
-
-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)).
+get_bytes(Stream, Length, Res) :- get_bytes(Stream, Length, [], Res).
+get_bytes(Stream, Length, Acc, Res) :-
+  (Length > 0 -> (
+    get_byte(Stream, B),
+    B =\= -1,
+    get_bytes(Stream, Length - 1, [B|Acc], Res)
+  ); reverse(Acc, Res)).
 
 sample_handler(http_request(Headers, _), Response) :-
     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"])).
\ No newline at end of file