Search in sources :

Example 1 with Request

use of suite.http.Http.Request in project suite by stupidsing.

the class HttpHandleSessionAuth method getHandler.

public Handler getHandler(BiPredicate<String, String> authenticate, Handler protectedHandler) {
    return new Handler() {

        public Response handle(Request request) {
            var current = System.currentTimeMillis();
            var sessionIdOpt = // 
            request.headers.getOpt(// 
            "Cookie").map(cookie -> HttpHeaderUtil.getCookieAttrs(cookie).get("session"));
            var session = sessionIdOpt.map(sm::get).or(null);
            Response response;
            if (Equals.ab(request.paths, PerList.of("login"))) {
                var attrs = HttpHeaderUtil.getPostedAttrs(request.in);
                var username = attrs.get("username");
                var password = attrs.get("password");
                var paths = HttpHeaderUtil.getPaths(attrs.get("path"));
                if (authenticate.test(username, password)) {
                    var sessionId = getRandomSessionId();
                    sm.put(sessionId, session = new Session(username, current));
                    var request1 = new // 
                    Request(// 
                    request.method, // 
                    request.server, // 
                    paths, // 
                    request.query, // 
                    request.headers, request.in);
                    response = showProtectedPage(request1, sessionId);
                } else
                    response = showLoginPage(paths, true);
            } else if (Equals.ab(request.paths, PerList.of("logout"))) {
                sessionIdOpt.sink(sm::remove);
                response = showLoginPage(PerList.end(), false);
            } else if (session != null && current < session.lastRequestDt.value() + timeoutDuration) {
                session.lastRequestDt.update(current);
                response = showProtectedPage(request, sessionIdOpt.g());
            } else
                response = showLoginPage(request.paths, false);
            return response;
        }

        private Response showProtectedPage(Request request, String sessionId) {
            var r = protectedHandler.handle(request);
            var headers1 = r.headers.put("Set-Cookie", "session=" + sessionId + "; Path=/site");
            return new Response(r.status, headers1, r.body);
        }

        private Response showLoginPage(PerList<String> redirectPath, boolean isLoginFailed) {
            var redirectPath1 = redirectPath.streamlet().map(p -> "/" + p).toJoinedString();
            return Response.of(Pull.from(// 
            "<html>" + // 
            "<head><title>Login</title></head>" + // 
            "<body>" + // 
            "<font face=\"Monospac821 BT,Monaco,Consolas\">" + // 
            (isLoginFailed ? "<b>LOGIN FAILED</b><p/>" : "") + // 
            "<form name=\"login\" action=\"login\" method=\"post\">" + // 
            "Username <input type=\"text\" name=\"username\" autofocus /><br/>" + // 
            "Password <input type=\"password\" name=\"password\" /><br/>" + "<input type=\"hidden\" name=\"path\" value=\"" + htmlUtil.encode(redirectPath1) + // 
            "\" />" + // 
            "<input type=\"submit\" value=\"Login\">" + // 
            "</form>" + // 
            "</font>" + // 
            "</body>" + "</html>"));
        }

        private String getRandomSessionId() {
            var bytes = new byte[16];
            random.nextBytes(bytes);
            return Build.string(sb -> {
                for (var b : bytes) sb.append(String.format("%02x", b));
            });
        }
    };
}
Also used : Response(suite.http.Http.Response) Build(primal.Verbs.Build) Random(java.util.Random) Session(suite.http.Http.Session) SecureRandom(java.security.SecureRandom) BiPredicate(java.util.function.BiPredicate) Response(suite.http.Http.Response) Request(suite.http.Http.Request) SessionManager(suite.http.Http.SessionManager) Pull(primal.MoreVerbs.Pull) Equals(primal.Verbs.Equals) PerList(primal.persistent.PerList) Handler(suite.http.Http.Handler) HtmlUtil(suite.util.HtmlUtil) Request(suite.http.Http.Request) Handler(suite.http.Http.Handler) PerList(primal.persistent.PerList) Session(suite.http.Http.Session)

Example 2 with Request

use of suite.http.Http.Request in project suite by stupidsing.

the class HttpIo method readRequest.

public Request readRequest(InputStream is0) {
    var ls = ReadLine.from(is0).split(" ");
    var headers = readHeaders(is0);
    return FixieArray.of(ls).map((method, url, protocol) -> {
        Fun2<String, String, Request> requestFun = (host, pqs) -> Split.strl(pqs, "?").map((path0, query) -> {
            var is1 = getContentStream(is0, headers);
            var path1 = path0.startsWith("/") ? path0 : "/" + path0;
            var path2 = ex(() -> URLDecoder.decode(path1, Utf8.charset));
            return // 
            Equals.string(protocol, "HTTP/1.1") ? // 
            new Request(method, host, path2, query, headers, Pull.from_(is1)) : fail("only HTTP/1.1 is supported");
        });
        var pp = Split.string(url, "://");
        return pp != null ? Split.strl(pp.v, "/").map(requestFun) : requestFun.apply("", url);
    });
}
Also used : OutputStream(java.io.OutputStream) FixieArray(primal.adt.FixieArray) Copy(suite.util.Copy) Fail.fail(primal.statics.Fail.fail) URLDecoder(java.net.URLDecoder) ReadStream(primal.io.ReadStream) IOException(java.io.IOException) To(suite.util.To) Math.min(java.lang.Math.min) Header(suite.http.Http.Header) Bytes(primal.primitive.adt.Bytes) Response(suite.http.Http.Response) Rethrow.ex(primal.statics.Rethrow.ex) Utf8(primal.Nouns.Utf8) ReadLine(primal.Verbs.ReadLine) Request(suite.http.Http.Request) Split(primal.MoreVerbs.Split) Math.max(java.lang.Math.max) Pull(primal.MoreVerbs.Pull) Fun2(primal.fp.Funs2.Fun2) Equals(primal.Verbs.Equals) Puller(primal.puller.Puller) InputStream(java.io.InputStream) Request(suite.http.Http.Request)

Example 3 with Request

use of suite.http.Http.Request in project suite by stupidsing.

the class HttpNio method listen.

private void listen(Reg reg) {
    var rw = new Object() {

        // 0 - read, 1 - write, 2 - close after all written
        private int stage = 0;

        private Bytes br = Bytes.empty;

        private Bytes bw = Bytes.empty;

        private Puller<Bytes> write;

        private Source<Boolean> eater = () -> parseLine(line -> handleRequest1stLine(line.trim(), response -> {
            var data = // 
            "HTTP/1.1 " + response.status + "\r\n" + response.headers.streamlet().map((k, v) -> k + ": " + v + "\r\n").toJoinedString() + "\r\n";
            stage = 1;
            if (response.body != null)
                write = Puller.concat(Pull.from(data), response.body);
            else {
                bw = Bytes.of(data.getBytes(Utf8.charset));
                response.write.f(bytes -> {
                    if (bytes != null)
                        bw = bw.append(bytes);
                    else
                        stage = 2;
                    listen();
                });
            }
        }));

        private void listen() {
            if (!bw.isEmpty())
                reg.listenWrite(() -> bw, this::written);
            else if (stage == 0)
                reg.listenRead(in -> {
                    read(in);
                    listen();
                });
            else if (stage == 1 && write != null)
                reg.listenWrite(() -> bw = write.pull(), this::written);
            else if (stage == 2)
                reg.listenWrite(() -> null, null);
            else if (stage == 3)
                reg.listen(0, null, null, null);
        }

        private void read(Bytes in) {
            if (in != null) {
                br = br.append(in);
                while (eater.g()) ;
            } else
                // closes connection
                write = Puller.empty();
        }

        private void written(int n) {
            if (0 <= n)
                bw = bw.range(n);
            else
                stage = 3;
            listen();
        }

        private void handleRequest1stLine(String line, Sink<Response> cb) {
            var hrhl = handleRequestHeaderLine(lines -> handleRequestBody(line, lines, cb));
            eater = () -> parseLine(hrhl);
        }

        private Sink<String> handleRequestHeaderLine(Sink<List<String>> cb) {
            var lines = new ArrayList<String>();
            return line0 -> {
                var line1 = line0.trim();
                if (!line1.isEmpty())
                    lines.add(line1);
                else
                    cb.f(lines);
            };
        }

        private void handleRequestBody(String line0, List<String> headerLines, Sink<Response> cb) {
            eater = () -> // 
            FixieArray.of(// 
            line0.split(" ")).map((method, url, proto) -> handleRequestBody(proto, method, url, headerLines, cb));
        }

        private // 
        boolean handleRequestBody(// 
        String proto, // 
        String method, // 
        String url, // 
        List<String> lines, Sink<Response> cb) {
            var headers = // 
            Read.from(// 
            lines).fold(new Header(), (headers_, line_) -> // 
            Split.strl(line_, // 
            ":").map((k, v) -> headers_.put(k, v)));
            var queue = new ArrayBlockingQueue<Bytes>(Buffer.size);
            Sink<Bytes> offer = queue::add;
            Source<Bytes> take = queue::poll;
            Fun2<String, String, Request> requestFun = (host, pqs) -> Split.strl(pqs, "?").map((path0, query) -> {
                var path1 = path0.startsWith("/") ? path0 : "/" + path0;
                var path2 = ex(() -> URLDecoder.decode(path1, Utf8.charset));
                return // 
                Equals.string(proto, "HTTP/1.1") ? // 
                new Request(method, host, path2, query, headers, Puller.of(take)) : fail("only HTTP/1.1 is supported");
            });
            var pp = Split.string(url, "://");
            var request = pp != null ? Split.strl(pp.v, "/").map(requestFun) : requestFun.apply("", url);
            var cl = request.headers.getOpt("Content-Length").map(Long::parseLong);
            var te = Equals.ab(request.headers.getOpt("Transfer-Encoding"), Opt.of("chunked"));
            Log_.info(request.getLogString());
            if (te)
                eater = handleChunkedRequestBody(request, offer, cb);
            else if (cl.hasValue())
                eater = handleRequestBody(request, offer, cl.g(), cb);
            else
                eater = handleRequestBody(request, offer, 0, cb);
            return true;
        }

        private // 
        Source<Boolean> handleRequestBody(// 
        Request request, // 
        Sink<Bytes> body, // 
        long contentLength, Sink<Response> cb) {
            return new Source<>() {

                private int n;

                public Boolean g() {
                    body.f(br);
                    var isOpen = br != null;
                    if (isOpen) {
                        n += br.size();
                        br = Bytes.empty;
                    }
                    if (!isOpen || contentLength <= n)
                        cb.f(handler.handle(request));
                    return false;
                }
            };
        }

        private Source<Boolean> handleChunkedRequestBody(Request request, Sink<Bytes> body, Sink<Response> cb) {
            return () -> {
                for (var i0 = 0; i0 < br.size(); i0++) if (br.get(i0) == 10) {
                    var line = new String(br.range(0, i0).toArray(), Utf8.charset);
                    var size = Integer.parseInt(line.trim(), 16);
                    for (var i1 = i0 + 1 + size; i1 < br.size(); i1++) if (br.get(i1) == 10) {
                        var chunk = br.range(i0 + 1, i1);
                        br = br.range(i1);
                        body.f(chunk);
                        return true;
                    }
                    if (size == 0)
                        cb.f(handler.handle(request));
                }
                return false;
            };
        }

        private boolean parseLine(Sink<String> handleLine) {
            for (var i = 0; i < br.size(); i++) if (br.get(i) == 10) {
                var line = new String(br.range(0, i).toArray(), Utf8.charset);
                br = br.range(i + 1);
                handleLine.f(line);
                return true;
            }
            return false;
        }
    };
    rw.listen();
}
Also used : FixieArray(primal.adt.FixieArray) Fail.fail(primal.statics.Fail.fail) URLDecoder(java.net.URLDecoder) Reg(suite.os.ListenNio.Reg) Sink(primal.fp.Funs.Sink) ArrayList(java.util.ArrayList) Response(suite.http.Http.Response) Utf8(primal.Nouns.Utf8) Request(suite.http.Http.Request) Split(primal.MoreVerbs.Split) Opt(primal.adt.Opt) Pull(primal.MoreVerbs.Pull) Handler(suite.http.Http.Handler) ListenNio(suite.os.ListenNio) Buffer(primal.Nouns.Buffer) Source(primal.fp.Funs.Source) Header(suite.http.Http.Header) Log_(primal.os.Log_) Read(primal.MoreVerbs.Read) Bytes(primal.primitive.adt.Bytes) ArrayBlockingQueue(java.util.concurrent.ArrayBlockingQueue) List(java.util.List) Rethrow.ex(primal.statics.Rethrow.ex) Fun2(primal.fp.Funs2.Fun2) Equals(primal.Verbs.Equals) Puller(primal.puller.Puller) ArrayList(java.util.ArrayList) Request(suite.http.Http.Request) Source(primal.fp.Funs.Source) Bytes(primal.primitive.adt.Bytes) Sink(primal.fp.Funs.Sink) Header(suite.http.Http.Header) ArrayBlockingQueue(java.util.concurrent.ArrayBlockingQueue) Puller(primal.puller.Puller) ArrayList(java.util.ArrayList) List(java.util.List)

Example 4 with Request

use of suite.http.Http.Request in project suite by stupidsing.

the class HttpProxy method serve.

public void serve() {
    var httpIo = new HttpIo();
    new Listen().io(port, (is, os) -> {
        var request0 = httpIo.readRequest(is);
        var pq = request0.path() + "?" + request0.query;
        Log_.info("PROXY " + pq);
        var headers1 = request0.headers.remove("Connection").put("Connection", "close");
        var request1 = new // 
        Request(// 
        request0.method, // 
        request0.server, // 
        request0.paths, // 
        request0.query, // 
        headers1, request0.in);
        try (// 
        var socket1 = connect(pq);
            // 
            var is0 = is;
            // 
            var os0 = os;
            // 
            var is1 = socket1.getInputStream();
            var os1 = socket1.getOutputStream()) {
            // 
            Start.thenJoin(// 
            () -> httpIo.writeRequest(os1, request1), () -> httpIo.writeResponse(os0, httpIo.readResponse(is1)));
        }
    });
}
Also used : Request(suite.http.Http.Request) Listen(suite.os.Listen)

Aggregations

Request (suite.http.Http.Request)4 Pull (primal.MoreVerbs.Pull)3 Equals (primal.Verbs.Equals)3 Response (suite.http.Http.Response)3 URLDecoder (java.net.URLDecoder)2 Split (primal.MoreVerbs.Split)2 Utf8 (primal.Nouns.Utf8)2 FixieArray (primal.adt.FixieArray)2 Fun2 (primal.fp.Funs2.Fun2)2 Bytes (primal.primitive.adt.Bytes)2 Puller (primal.puller.Puller)2 Fail.fail (primal.statics.Fail.fail)2 Rethrow.ex (primal.statics.Rethrow.ex)2 Handler (suite.http.Http.Handler)2 Header (suite.http.Http.Header)2 IOException (java.io.IOException)1 InputStream (java.io.InputStream)1 OutputStream (java.io.OutputStream)1 Math.max (java.lang.Math.max)1 Math.min (java.lang.Math.min)1