From 58a5359d4933c86d5e005a436d3655be955baa7c Mon Sep 17 00:00:00 2001 From: Karim Date: Sun, 15 Dec 2024 00:40:58 +0300 Subject: [PATCH] fix https://github.com/yegor256/takes/issues/945 --- .../java/org/takes/facets/auth/PsBasic.java | 6 +- .../java/org/takes/facets/auth/PsByFlag.java | 4 +- .../org/takes/facets/auth/XeLogoutLink.java | 4 +- .../takes/facets/auth/social/PsFacebook.java | 4 +- .../takes/facets/auth/social/PsGithub.java | 4 +- .../takes/facets/auth/social/PsGoogle.java | 4 +- .../takes/facets/auth/social/PsLinkedin.java | 4 +- .../facets/auth/social/XeFacebookLink.java | 4 +- .../facets/auth/social/XeGithubLink.java | 4 +- .../facets/auth/social/XeGoogleLink.java | 7 +- .../org/takes/facets/fallback/FbLog4j.java | 4 +- .../org/takes/facets/fallback/FbSlf4j.java | 4 +- .../org/takes/facets/fallback/TkFallback.java | 4 +- .../java/org/takes/facets/fork/FkParams.java | 4 +- .../java/org/takes/facets/fork/FkRegex.java | 4 +- src/main/java/org/takes/rq/RqHref.java | 158 ------------------ src/main/java/org/takes/rq/RqHrefBase.java | 81 +++++++++ src/main/java/org/takes/rq/RqHrefSmart.java | 128 ++++++++++++++ src/main/java/org/takes/rs/xe/XeLinkHome.java | 5 +- src/main/java/org/takes/rs/xe/XeLinkSelf.java | 4 +- .../takes/servlet/HttpServletRequestFake.java | 4 +- src/main/java/org/takes/tk/TkClasspath.java | 4 +- src/main/java/org/takes/tk/TkFiles.java | 4 +- src/main/java/org/takes/tk/TkSlf4j.java | 4 +- src/main/java/org/takes/tk/TkSslOnly.java | 4 +- src/main/java/org/takes/tk/TkVerbose.java | 4 +- .../facets/auth/social/PsGoogleTest.java | 8 +- .../facets/auth/social/PsLinkedinTest.java | 4 +- src/test/java/org/takes/rq/RqHrefTest.java | 28 ++-- src/test/java/org/takes/tk/TkProxyTest.java | 4 +- 30 files changed, 281 insertions(+), 228 deletions(-) create mode 100644 src/main/java/org/takes/rq/RqHrefBase.java create mode 100644 src/main/java/org/takes/rq/RqHrefSmart.java diff --git a/src/main/java/org/takes/facets/auth/PsBasic.java b/src/main/java/org/takes/facets/auth/PsBasic.java index ebf7bf19d..cbbb6b7ab 100644 --- a/src/main/java/org/takes/facets/auth/PsBasic.java +++ b/src/main/java/org/takes/facets/auth/PsBasic.java @@ -45,7 +45,7 @@ import org.takes.facets.forward.RsForward; import org.takes.misc.Opt; import org.takes.rq.RqHeaders; -import org.takes.rq.RqHref; +import org.takes.rq.RqHrefBase; import org.takes.rs.RsWithHeader; /** @@ -99,7 +99,7 @@ public Opt enter(final Request request) throws IOException { ) ), HttpURLConnection.HTTP_UNAUTHORIZED, - new RqHref.Base(request).href() + new RqHrefBase(request).href() ); } final String decoded = new IoCheckedText( @@ -126,7 +126,7 @@ public Opt enter(final Request request) throws IOException { ) ), HttpURLConnection.HTTP_UNAUTHORIZED, - new RqHref.Base(request).href() + new RqHrefBase(request).href() ); } return identity; diff --git a/src/main/java/org/takes/facets/auth/PsByFlag.java b/src/main/java/org/takes/facets/auth/PsByFlag.java index 4b03360a3..5a9d5ab41 100644 --- a/src/main/java/org/takes/facets/auth/PsByFlag.java +++ b/src/main/java/org/takes/facets/auth/PsByFlag.java @@ -33,7 +33,7 @@ import org.takes.Request; import org.takes.Response; import org.takes.misc.Opt; -import org.takes.rq.RqHref; +import org.takes.rq.RqHrefBase; /** * Passes by flag. @@ -94,7 +94,7 @@ public PsByFlag(final String flg, final Map map) { @Override public Opt enter(final Request req) throws Exception { - final Iterator flg = new RqHref.Base(req).href() + final Iterator flg = new RqHrefBase(req).href() .param(this.flag).iterator(); Opt user = new Opt.Empty<>(); if (flg.hasNext()) { diff --git a/src/main/java/org/takes/facets/auth/XeLogoutLink.java b/src/main/java/org/takes/facets/auth/XeLogoutLink.java index c3ab85f15..b66ccbfd4 100644 --- a/src/main/java/org/takes/facets/auth/XeLogoutLink.java +++ b/src/main/java/org/takes/facets/auth/XeLogoutLink.java @@ -26,7 +26,7 @@ import java.io.IOException; import lombok.EqualsAndHashCode; import org.takes.Request; -import org.takes.rq.RqHref; +import org.takes.rq.RqHrefBase; import org.takes.rs.xe.XeLink; import org.takes.rs.xe.XeWrap; @@ -62,7 +62,7 @@ public XeLogoutLink(final Request req, final String rel, super( new XeLink( rel, - new RqHref.Base(req).href().with( + new RqHrefBase(req).href().with( flag, PsLogout.class.getSimpleName() ).toString() ) diff --git a/src/main/java/org/takes/facets/auth/social/PsFacebook.java b/src/main/java/org/takes/facets/auth/social/PsFacebook.java index 9d72ed292..a342f7b3d 100644 --- a/src/main/java/org/takes/facets/auth/social/PsFacebook.java +++ b/src/main/java/org/takes/facets/auth/social/PsFacebook.java @@ -46,7 +46,7 @@ import org.takes.facets.auth.Pass; import org.takes.misc.Href; import org.takes.misc.Opt; -import org.takes.rq.RqHref; +import org.takes.rq.RqHrefBase; /** * Facebook OAuth landing/callback page. @@ -142,7 +142,7 @@ public PsFacebook(final String fapp, final String fkey) { @Override public Opt enter(final Request trequest) throws IOException { - final Href href = new RqHref.Base(trequest).href(); + final Href href = new RqHrefBase(trequest).href(); final Iterator code = href.param(PsFacebook.CODE).iterator(); if (!code.hasNext()) { throw new HttpException( diff --git a/src/main/java/org/takes/facets/auth/social/PsGithub.java b/src/main/java/org/takes/facets/auth/social/PsGithub.java index c8b35bf54..287760e10 100644 --- a/src/main/java/org/takes/facets/auth/social/PsGithub.java +++ b/src/main/java/org/takes/facets/auth/social/PsGithub.java @@ -41,7 +41,7 @@ import org.takes.facets.auth.Pass; import org.takes.misc.Href; import org.takes.misc.Opt; -import org.takes.rq.RqHref; +import org.takes.rq.RqHrefBase; /** * Github OAuth landing/callback page. @@ -116,7 +116,7 @@ public PsGithub(final String gapp, final String gkey) { @Override public Opt enter(final Request request) throws IOException { - final Href href = new RqHref.Base(request).href(); + final Href href = new RqHrefBase(request).href(); final Iterator code = href.param(PsGithub.CODE).iterator(); if (!code.hasNext()) { throw new HttpException( diff --git a/src/main/java/org/takes/facets/auth/social/PsGoogle.java b/src/main/java/org/takes/facets/auth/social/PsGoogle.java index ec7017438..30ece0775 100644 --- a/src/main/java/org/takes/facets/auth/social/PsGoogle.java +++ b/src/main/java/org/takes/facets/auth/social/PsGoogle.java @@ -40,7 +40,7 @@ import org.takes.facets.auth.Pass; import org.takes.misc.Href; import org.takes.misc.Opt; -import org.takes.rq.RqHref; +import org.takes.rq.RqHrefBase; /** * Google OAuth landing/callback page. @@ -145,7 +145,7 @@ public PsGoogle(final String gapp, final String gkey, @Override public Opt enter(final Request request) throws IOException { - final Href href = new RqHref.Base(request).href(); + final Href href = new RqHrefBase(request).href(); final Iterator code = href.param(PsGoogle.CODE).iterator(); if (!code.hasNext()) { throw new HttpException( diff --git a/src/main/java/org/takes/facets/auth/social/PsLinkedin.java b/src/main/java/org/takes/facets/auth/social/PsLinkedin.java index e099ba9da..f27c23d62 100644 --- a/src/main/java/org/takes/facets/auth/social/PsLinkedin.java +++ b/src/main/java/org/takes/facets/auth/social/PsLinkedin.java @@ -41,7 +41,7 @@ import org.takes.facets.auth.Pass; import org.takes.misc.Href; import org.takes.misc.Opt; -import org.takes.rq.RqHref; +import org.takes.rq.RqHrefBase; /** * Linkedin OAuth landing/callback page. @@ -110,7 +110,7 @@ public PsLinkedin(final Href thref, final Href ahref, @Override public Opt enter(final Request request) throws IOException { - final Href href = new RqHref.Base(request).href(); + final Href href = new RqHrefBase(request).href(); final Iterator code = href.param(PsLinkedin.CODE).iterator(); if (!code.hasNext()) { throw new HttpException( diff --git a/src/main/java/org/takes/facets/auth/social/XeFacebookLink.java b/src/main/java/org/takes/facets/auth/social/XeFacebookLink.java index 85546b321..f759efc71 100644 --- a/src/main/java/org/takes/facets/auth/social/XeFacebookLink.java +++ b/src/main/java/org/takes/facets/auth/social/XeFacebookLink.java @@ -28,7 +28,7 @@ import org.takes.Request; import org.takes.facets.auth.PsByFlag; import org.takes.misc.Href; -import org.takes.rq.RqHref; +import org.takes.rq.RqHrefBase; import org.takes.rs.xe.XeLink; import org.takes.rs.xe.XeSource; import org.takes.rs.xe.XeWrap; @@ -86,7 +86,7 @@ private static XeSource make(final Request req, final CharSequence app, .with("client_id", app) .with( "redirect_uri", - new RqHref.Base(req).href() + new RqHrefBase(req).href() .with(flag, PsFacebook.class.getSimpleName()) ) ); diff --git a/src/main/java/org/takes/facets/auth/social/XeGithubLink.java b/src/main/java/org/takes/facets/auth/social/XeGithubLink.java index 991a7313e..76b849b1f 100644 --- a/src/main/java/org/takes/facets/auth/social/XeGithubLink.java +++ b/src/main/java/org/takes/facets/auth/social/XeGithubLink.java @@ -28,7 +28,7 @@ import org.takes.Request; import org.takes.facets.auth.PsByFlag; import org.takes.misc.Href; -import org.takes.rq.RqHref; +import org.takes.rq.RqHrefBase; import org.takes.rs.xe.XeLink; import org.takes.rs.xe.XeSource; import org.takes.rs.xe.XeWrap; @@ -86,7 +86,7 @@ private static XeSource make(final Request req, final CharSequence app, .with("client_id", app) .with( "redirect_uri", - new RqHref.Base(req).href() + new RqHrefBase(req).href() .with(flag, PsGithub.class.getSimpleName()) ) ); diff --git a/src/main/java/org/takes/facets/auth/social/XeGoogleLink.java b/src/main/java/org/takes/facets/auth/social/XeGoogleLink.java index fc5367a77..0e4c9ebe7 100644 --- a/src/main/java/org/takes/facets/auth/social/XeGoogleLink.java +++ b/src/main/java/org/takes/facets/auth/social/XeGoogleLink.java @@ -27,7 +27,8 @@ import lombok.EqualsAndHashCode; import org.takes.Request; import org.takes.misc.Href; -import org.takes.rq.RqHref; +import org.takes.rq.RqHrefBase; +import org.takes.rq.RqHrefSmart; import org.takes.rs.xe.XeLink; import org.takes.rs.xe.XeSource; import org.takes.rs.xe.XeWrap; @@ -50,7 +51,7 @@ public final class XeGoogleLink extends XeWrap { */ public XeGoogleLink(final Request req, final CharSequence app) throws IOException { - this(req, app, new RqHref.Smart(new RqHref.Base(req)).home()); + this(req, app, new RqHrefSmart(new RqHrefBase(req)).home()); } /** @@ -100,7 +101,7 @@ private static XeSource make(final Request req, final CharSequence app, .with("client_id", app) .with("redirect_uri", redir) .with("response_type", "code") - .with("state", new RqHref.Base(req).href()) + .with("state", new RqHrefBase(req).href()) .with( "scope", "https://www.googleapis.com/auth/userinfo.profile" diff --git a/src/main/java/org/takes/facets/fallback/FbLog4j.java b/src/main/java/org/takes/facets/fallback/FbLog4j.java index 14c7f8f7d..670b248c0 100644 --- a/src/main/java/org/takes/facets/fallback/FbLog4j.java +++ b/src/main/java/org/takes/facets/fallback/FbLog4j.java @@ -29,7 +29,7 @@ import org.cactoos.bytes.BytesOf; import org.cactoos.text.TextOf; import org.takes.misc.Opt; -import org.takes.rq.RqHref; +import org.takes.rq.RqHrefBase; import org.takes.rq.RqMethod; /** @@ -61,7 +61,7 @@ private static void log(final RqFallback req) throws IOException { String.format( "%s %s failed with %s: %s", new RqMethod.Base(req).method(), - new RqHref.Base(req).href(), + new RqHrefBase(req).href(), req.code(), new TextOf(new BytesOf(req.throwable())) ) diff --git a/src/main/java/org/takes/facets/fallback/FbSlf4j.java b/src/main/java/org/takes/facets/fallback/FbSlf4j.java index 0e151fe8e..ad1b05f5f 100644 --- a/src/main/java/org/takes/facets/fallback/FbSlf4j.java +++ b/src/main/java/org/takes/facets/fallback/FbSlf4j.java @@ -30,7 +30,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.takes.misc.Opt; -import org.takes.rq.RqHref; +import org.takes.rq.RqHrefBase; import org.takes.rq.RqMethod; /** @@ -69,7 +69,7 @@ private static void log(final RqFallback req) throws IOException { FbSlf4j.LOGGER.error( "{} {} failed with {}: {}", new RqMethod.Base(req).method(), - new RqHref.Base(req).href(), + new RqHrefBase(req).href(), req.code(), new TextOf(new BytesOf(req.throwable())) ); diff --git a/src/main/java/org/takes/facets/fallback/TkFallback.java b/src/main/java/org/takes/facets/fallback/TkFallback.java index 81080fadd..ecca9946a 100644 --- a/src/main/java/org/takes/facets/fallback/TkFallback.java +++ b/src/main/java/org/takes/facets/fallback/TkFallback.java @@ -34,7 +34,7 @@ import org.takes.Response; import org.takes.Take; import org.takes.misc.Opt; -import org.takes.rq.RqHref; +import org.takes.rq.RqHrefBase; import org.takes.rq.RqMethod; import org.takes.rs.ResponseOf; import org.takes.tk.TkWrap; @@ -232,7 +232,7 @@ private static Throwable error(final Throwable exp, final Request req, String.format( "[%s %s] failed in %s: %s", new RqMethod.Base(req).method(), - new RqHref.Base(req).href(), + new RqHrefBase(req).href(), time, TkFallback.msg(exp) ), exp diff --git a/src/main/java/org/takes/facets/fork/FkParams.java b/src/main/java/org/takes/facets/fork/FkParams.java index e24ffc999..a029a7fa2 100644 --- a/src/main/java/org/takes/facets/fork/FkParams.java +++ b/src/main/java/org/takes/facets/fork/FkParams.java @@ -30,7 +30,7 @@ import org.takes.Response; import org.takes.Take; import org.takes.misc.Opt; -import org.takes.rq.RqHref; +import org.takes.rq.RqHrefBase; /** * Fork by query params and their values, matched by regular express. @@ -82,7 +82,7 @@ public FkParams(final String param, final Pattern ptn, final Take tke) { @Override public Opt route(final Request req) throws Exception { - final Iterator params = new RqHref.Base(req).href() + final Iterator params = new RqHrefBase(req).href() .param(this.name).iterator(); final Opt resp; if (params.hasNext() diff --git a/src/main/java/org/takes/facets/fork/FkRegex.java b/src/main/java/org/takes/facets/fork/FkRegex.java index caa58c09b..d66d839ca 100644 --- a/src/main/java/org/takes/facets/fork/FkRegex.java +++ b/src/main/java/org/takes/facets/fork/FkRegex.java @@ -33,7 +33,7 @@ import org.takes.Response; import org.takes.Take; import org.takes.misc.Opt; -import org.takes.rq.RqHref; +import org.takes.rq.RqHrefBase; import org.takes.tk.TkFixed; import org.takes.tk.TkText; @@ -202,7 +202,7 @@ public FkRegex setRemoveTrailingSlash(final boolean enabled) { @Override public Opt route(final Request req) throws Exception { - String path = new RqHref.Base(req).href().path(); + String path = new RqHrefBase(req).href().path(); if ( this.removeslash && path.length() > 1 diff --git a/src/main/java/org/takes/rq/RqHref.java b/src/main/java/org/takes/rq/RqHref.java index 7bdf5eefa..90a659d1d 100644 --- a/src/main/java/org/takes/rq/RqHref.java +++ b/src/main/java/org/takes/rq/RqHref.java @@ -24,16 +24,6 @@ package org.takes.rq; import java.io.IOException; -import java.io.InputStream; -import java.net.HttpURLConnection; -import java.net.URI; -import java.util.Iterator; -import lombok.EqualsAndHashCode; -import org.cactoos.Text; -import org.cactoos.text.TextOf; -import org.cactoos.text.Trimmed; -import org.cactoos.text.UncheckedText; -import org.takes.HttpException; import org.takes.Request; import org.takes.misc.Href; @@ -52,153 +42,5 @@ public interface RqHref extends Request { * @throws IOException If fails */ Href href() throws IOException; - - /** - * Request decorator, for HTTP URI query parsing. - * - *

The class is immutable and thread-safe. - * @since 0.13.1 - */ - @EqualsAndHashCode(callSuper = true) - final class Base extends RqWrap implements RqHref { - /** - * Ctor. - * @param req Original request - */ - public Base(final Request req) { - super(req); - } - - @Override - public Href href() throws IOException { - final String uri = new RqRequestLine.Base(this).uri(); - final Iterator hosts = new RqHeaders.Base(this) - .header("host").iterator(); - final Iterator protos = new RqHeaders.Base(this) - .header("x-forwarded-proto").iterator(); - final Text host; - if (hosts.hasNext()) { - host = new Trimmed(new TextOf(hosts.next())); - } else { - host = new TextOf("localhost"); - } - final Text proto; - if (protos.hasNext()) { - proto = new Trimmed(new TextOf(protos.next())); - } else { - proto = new TextOf("http"); - } - return new Href( - String.format( - "%s://%s%s", - new UncheckedText(proto).asString(), - new UncheckedText(host).asString(), - uri - ) - ); - } - } - - /** - * Smart decorator, with extra features. - * - *

The class is immutable and thread-safe. - * - * @since 0.14 - */ - @EqualsAndHashCode - final class Smart implements RqHref { - /** - * Original. - */ - private final RqHref origin; - - /** - * Ctor. - * @param req Original request - * @since 1.4 - */ - public Smart(final Request req) { - this(new RqHref.Base(req)); - } - - /** - * Ctor. - * @param req Original request - */ - public Smart(final RqHref req) { - this.origin = req; - } - - @Override - public Href href() throws IOException { - return this.origin.href(); - } - - @Override - public Iterable head() throws IOException { - return this.origin.head(); - } - - @Override - public InputStream body() throws IOException { - return this.origin.body(); - } - - /** - * Get self. - * @return Self page, full URL - * @throws IOException If fails - * @since 0.14 - */ - public Href home() throws IOException { - final URI full = URI.create(this.href().toString()); - return new Href( - String.format( - "%s://%s/", - full.getScheme(), - full.getHost() - ) - ); - } - - /** - * Get param or throw HTTP exception. - * @param name Name of query param - * @return Value of it - * @throws IOException If fails - */ - public String single(final CharSequence name) throws IOException { - final Iterator params = this.href().param(name).iterator(); - if (!params.hasNext()) { - throw new HttpException( - HttpURLConnection.HTTP_BAD_REQUEST, - String.format( - "query param \"%s\" is mandatory", name - ) - ); - } - return params.next(); - } - - /** - * Get param or default. - * @param name Name of query param - * @param def Default, if not found - * @return Value of it - * @throws IOException If fails - */ - public String single(final CharSequence name, final CharSequence def) - throws IOException { - final String value; - final Iterator params = this.href().param(name).iterator(); - if (params.hasNext()) { - value = params.next(); - } else { - value = def.toString(); - } - return value; - } - } } diff --git a/src/main/java/org/takes/rq/RqHrefBase.java b/src/main/java/org/takes/rq/RqHrefBase.java new file mode 100644 index 000000000..340f50377 --- /dev/null +++ b/src/main/java/org/takes/rq/RqHrefBase.java @@ -0,0 +1,81 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2014-2024 Yegor Bugayenko + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package org.takes.rq; + +import java.io.IOException; +import java.util.Iterator; +import lombok.EqualsAndHashCode; +import org.cactoos.Text; +import org.cactoos.text.TextOf; +import org.cactoos.text.Trimmed; +import org.cactoos.text.UncheckedText; +import org.takes.Request; +import org.takes.misc.Href; + +/** + * Request decorator, for HTTP URI query parsing. + * + *

The class is immutable and thread-safe. + * + * @since 0.13.1 + */ +@EqualsAndHashCode(callSuper = true) +public final class RqHrefBase extends RqWrap implements RqHref { + /** + * Ctor. + * @param req Original request + */ + public RqHrefBase(final Request req) { + super(req); + } + + @Override + public Href href() throws IOException { + final String uri = new RqRequestLine.Base(this).uri(); + final Iterator hosts = new RqHeaders.Base(this) + .header("host").iterator(); + final Iterator protos = new RqHeaders.Base(this) + .header("x-forwarded-proto").iterator(); + final Text host; + if (hosts.hasNext()) { + host = new Trimmed(new TextOf(hosts.next())); + } else { + host = new TextOf("localhost"); + } + final Text proto; + if (protos.hasNext()) { + proto = new Trimmed(new TextOf(protos.next())); + } else { + proto = new TextOf("http"); + } + return new Href( + String.format( + "%s://%s%s", + new UncheckedText(proto).asString(), + new UncheckedText(host).asString(), + uri + ) + ); + } +} diff --git a/src/main/java/org/takes/rq/RqHrefSmart.java b/src/main/java/org/takes/rq/RqHrefSmart.java new file mode 100644 index 000000000..8644e4dd4 --- /dev/null +++ b/src/main/java/org/takes/rq/RqHrefSmart.java @@ -0,0 +1,128 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2014-2024 Yegor Bugayenko + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package org.takes.rq; + +import java.io.IOException; +import java.io.InputStream; +import java.net.HttpURLConnection; +import java.net.URI; +import java.util.Iterator; +import lombok.EqualsAndHashCode; +import org.takes.HttpException; +import org.takes.Request; +import org.takes.misc.Href; + +/** + * Smart decorator, with extra features. + *

The class is immutable and thread-safe. + * @since 0.14 + */ +@EqualsAndHashCode +public final class RqHrefSmart implements RqHref { + /** + * Original. + */ + private final RqHref origin; + + /** + * Ctor. + * @param req Original request + * @since 1.4 + */ + public RqHrefSmart(final Request req) { + this(new RqHrefSmart(req)); + } + + /** + * Ctor. + * @param req Original request + */ + public RqHrefSmart(final RqHref req) { + this.origin = req; + } + + @Override + public Href href() throws IOException { + return this.origin.href(); + } + + @Override + public Iterable head() throws IOException { + return this.origin.head(); + } + + @Override + public InputStream body() throws IOException { + return this.origin.body(); + } + + /** + * Get self. + * @return Self page, full URL + * @throws IOException If fails + * @since 0.14 + */ + public Href home() throws IOException { + final URI full = URI.create(this.href().toString()); + return new Href( + String.format("%s://%s/", full.getScheme(), full.getHost()) + ); + } + + /** + * Get param or throw HTTP exception. + * @param name Name of query param + * @return Value of it + * @throws IOException If fails + */ + public String single(final CharSequence name) throws IOException { + final Iterator params = this.href().param(name).iterator(); + if (!params.hasNext()) { + throw new HttpException( + HttpURLConnection.HTTP_BAD_REQUEST, + String.format("query param \"%s\" is mandatory", name) + ); + } + return params.next(); + } + + /** + * Get param or default. + * @param name Name of query param + * @param def Default, if not found + * @return Value of it + * @throws IOException If fails + */ + public String single(final CharSequence name, final CharSequence def) + throws IOException { + final String value; + final Iterator params = this.href().param(name).iterator(); + if (params.hasNext()) { + value = params.next(); + } else { + value = def.toString(); + } + return value; + } +} diff --git a/src/main/java/org/takes/rs/xe/XeLinkHome.java b/src/main/java/org/takes/rs/xe/XeLinkHome.java index 69fb9ddd2..bc61ac591 100644 --- a/src/main/java/org/takes/rs/xe/XeLinkHome.java +++ b/src/main/java/org/takes/rs/xe/XeLinkHome.java @@ -25,7 +25,8 @@ import lombok.EqualsAndHashCode; import org.takes.Request; -import org.takes.rq.RqHref; +import org.takes.rq.RqHrefBase; +import org.takes.rq.RqHrefSmart; /** * Xembly source to create an HOME Atom LINK element. @@ -45,7 +46,7 @@ public XeLinkHome(final Request req) { super( () -> new XeLink( "home", - new RqHref.Smart(new RqHref.Base(req)).home() + new RqHrefSmart(new RqHrefBase(req)).home() ).toXembly() ); } diff --git a/src/main/java/org/takes/rs/xe/XeLinkSelf.java b/src/main/java/org/takes/rs/xe/XeLinkSelf.java index 5752919c1..c48c2e135 100644 --- a/src/main/java/org/takes/rs/xe/XeLinkSelf.java +++ b/src/main/java/org/takes/rs/xe/XeLinkSelf.java @@ -25,7 +25,7 @@ import lombok.EqualsAndHashCode; import org.takes.Request; -import org.takes.rq.RqHref; +import org.takes.rq.RqHrefBase; /** * Xembly source to create an SELF Atom LINK element. @@ -44,7 +44,7 @@ public final class XeLinkSelf extends XeWrap { public XeLinkSelf(final Request req) { super( () -> new XeLink( - "self", new RqHref.Base(req).href() + "self", new RqHrefBase(req).href() ).toXembly() ); } diff --git a/src/main/java/org/takes/servlet/HttpServletRequestFake.java b/src/main/java/org/takes/servlet/HttpServletRequestFake.java index 1988aab45..58aa0618a 100644 --- a/src/main/java/org/takes/servlet/HttpServletRequestFake.java +++ b/src/main/java/org/takes/servlet/HttpServletRequestFake.java @@ -51,7 +51,7 @@ import java.util.NoSuchElementException; import org.takes.Request; import org.takes.rq.RqHeaders; -import org.takes.rq.RqHref; +import org.takes.rq.RqHrefBase; import org.takes.rq.RqMethod; /** @@ -172,7 +172,7 @@ public int getLocalPort() { @Override public String getRequestURI() { try { - return new RqHref.Base(this.request).href().path(); + return new RqHrefBase(this.request).href().path(); } catch (final IOException ex) { throw new IllegalStateException( "Failed to get HREF from Request", diff --git a/src/main/java/org/takes/tk/TkClasspath.java b/src/main/java/org/takes/tk/TkClasspath.java index 9c52fa7dd..955b51219 100644 --- a/src/main/java/org/takes/tk/TkClasspath.java +++ b/src/main/java/org/takes/tk/TkClasspath.java @@ -32,7 +32,7 @@ import org.takes.Request; import org.takes.Response; import org.takes.Take; -import org.takes.rq.RqHref; +import org.takes.rq.RqHrefBase; import org.takes.rs.RsWithBody; /** @@ -89,7 +89,7 @@ public TkClasspath(final String prefix) { @Override public Response act(final Request request) throws IOException { final String name = String.format( - "%s%s", prefix, new RqHref.Base(request).href().path() + "%s%s", prefix, new RqHrefBase(request).href().path() ); final InputStream input = this.getClass() .getResourceAsStream(name); diff --git a/src/main/java/org/takes/tk/TkFiles.java b/src/main/java/org/takes/tk/TkFiles.java index 6b842d3dd..16fc09cb2 100644 --- a/src/main/java/org/takes/tk/TkFiles.java +++ b/src/main/java/org/takes/tk/TkFiles.java @@ -29,7 +29,7 @@ import lombok.ToString; import org.cactoos.io.InputOf; import org.takes.HttpException; -import org.takes.rq.RqHref; +import org.takes.rq.RqHrefBase; import org.takes.rs.RsWithBody; /** @@ -73,7 +73,7 @@ public TkFiles(final File base) { super( request -> { final File file = new File( - base, new RqHref.Base(request).href().path() + base, new RqHrefBase(request).href().path() ); if (!file.exists()) { throw new HttpException( diff --git a/src/main/java/org/takes/tk/TkSlf4j.java b/src/main/java/org/takes/tk/TkSlf4j.java index 279b7a743..654435cef 100644 --- a/src/main/java/org/takes/tk/TkSlf4j.java +++ b/src/main/java/org/takes/tk/TkSlf4j.java @@ -38,7 +38,7 @@ import org.takes.Request; import org.takes.Response; import org.takes.Take; -import org.takes.rq.RqHref; +import org.takes.rq.RqHrefBase; import org.takes.rq.RqMethod; /** @@ -101,7 +101,7 @@ public Response act(final Request req) throws Exception { new FormattedText( "[%s %s]", new RqMethod.Base(req).method(), - new RqHref.Base(req).href() + new RqHrefBase(req).href() ), new FormattedText(params.getKey(), params.getValue()), new FormattedText("in %d ms", time.value() - start) diff --git a/src/main/java/org/takes/tk/TkSslOnly.java b/src/main/java/org/takes/tk/TkSslOnly.java index f4150741d..a64585d19 100644 --- a/src/main/java/org/takes/tk/TkSslOnly.java +++ b/src/main/java/org/takes/tk/TkSslOnly.java @@ -29,7 +29,7 @@ import org.takes.Response; import org.takes.Take; import org.takes.rq.RqHeaders; -import org.takes.rq.RqHref; +import org.takes.rq.RqHrefBase; import org.takes.rs.RsRedirect; /** @@ -58,7 +58,7 @@ public TkSslOnly(final Take take) { @Override public Response act(final Request req) throws Exception { - final String href = new RqHref.Base(req).href().toString(); + final String href = new RqHrefBase(req).href().toString(); final String proto = new RqHeaders.Smart(req).single("x-forwarded-proto", "https"); final Response answer; if ("https".equalsIgnoreCase(proto)) { diff --git a/src/main/java/org/takes/tk/TkVerbose.java b/src/main/java/org/takes/tk/TkVerbose.java index eab847287..3a245e2ad 100644 --- a/src/main/java/org/takes/tk/TkVerbose.java +++ b/src/main/java/org/takes/tk/TkVerbose.java @@ -27,7 +27,7 @@ import lombok.ToString; import org.takes.HttpException; import org.takes.Take; -import org.takes.rq.RqHref; +import org.takes.rq.RqHrefBase; import org.takes.rq.RqMethod; /** @@ -56,7 +56,7 @@ public TkVerbose(final Take take) { String.format( "%s %s", new RqMethod.Base(request).method(), - new RqHref.Base(request).href() + new RqHrefBase(request).href() ), ex ); diff --git a/src/test/java/org/takes/facets/auth/social/PsGoogleTest.java b/src/test/java/org/takes/facets/auth/social/PsGoogleTest.java index 225c9b8a9..1b912f5ba 100644 --- a/src/test/java/org/takes/facets/auth/social/PsGoogleTest.java +++ b/src/test/java/org/takes/facets/auth/social/PsGoogleTest.java @@ -38,7 +38,7 @@ import org.takes.http.FtRemote; import org.takes.rq.RqFake; import org.takes.rq.RqGreedy; -import org.takes.rq.RqHref; +import org.takes.rq.RqHrefBase; import org.takes.rq.RqPrint; import org.takes.rq.form.RqFormBase; import org.takes.rq.form.RqFormSmart; @@ -145,7 +145,7 @@ void logsIn() throws Exception { ) ); MatcherAssert.assertThat( - new RqHref.Base(req).href() + new RqHrefBase(req).href() .param(PsGoogleTest.ACCESS_TOKEN) .iterator().next(), Matchers.containsString(PsGoogleTest.GOOGLE_TOKEN) @@ -210,7 +210,7 @@ void badGoogleResponse() { ) ); MatcherAssert.assertThat( - new RqHref.Base(req).href() + new RqHrefBase(req).href() .param(PsGoogleTest.ACCESS_TOKEN) .iterator().next(), Matchers.containsString(PsGoogleTest.GOOGLE_TOKEN) @@ -252,7 +252,7 @@ void noDisplayNameResponse() throws Exception { ) ); MatcherAssert.assertThat( - new RqHref.Base(req).href() + new RqHrefBase(req).href() .param(PsGoogleTest.ACCESS_TOKEN) .iterator().next(), Matchers.containsString(PsGoogleTest.GOOGLE_TOKEN) diff --git a/src/test/java/org/takes/facets/auth/social/PsLinkedinTest.java b/src/test/java/org/takes/facets/auth/social/PsLinkedinTest.java index df97a4355..9e3d4b327 100644 --- a/src/test/java/org/takes/facets/auth/social/PsLinkedinTest.java +++ b/src/test/java/org/takes/facets/auth/social/PsLinkedinTest.java @@ -42,7 +42,7 @@ import org.takes.http.FtRemote; import org.takes.misc.Href; import org.takes.rq.RqFake; -import org.takes.rq.RqHref; +import org.takes.rq.RqHrefBase; import org.takes.rq.RqPrint; import org.takes.rs.RsJson; @@ -140,7 +140,7 @@ public Response act(final Request req) throws IOException { ) ); MatcherAssert.assertThat( - new RqHref.Base(req).href().toString(), + new RqHrefBase(req).href().toString(), Matchers.endsWith(this.tokenpath) ); return new RsJson( diff --git a/src/test/java/org/takes/rq/RqHrefTest.java b/src/test/java/org/takes/rq/RqHrefTest.java index ab2ed33cd..508512576 100644 --- a/src/test/java/org/takes/rq/RqHrefTest.java +++ b/src/test/java/org/takes/rq/RqHrefTest.java @@ -33,7 +33,7 @@ import org.takes.HttpException; /** - * Test case for {@link RqHref.Base}. + * Test case for {@link RqHrefBase}. * @since 0.1 */ final class RqHrefTest { @@ -41,7 +41,7 @@ final class RqHrefTest { @Test void parsesHttpQuery() throws IOException { MatcherAssert.assertThat( - new RqHref.Base( + new RqHrefBase( new RqFake( Arrays.asList( "GET /h?a=3", @@ -58,7 +58,7 @@ void parsesHttpQuery() throws IOException { @Test void takesProtoIntoAccount() throws IOException { MatcherAssert.assertThat( - new RqHref.Base( + new RqHrefBase( new RqFake( Arrays.asList( "GET /test1", @@ -75,7 +75,7 @@ void takesProtoIntoAccount() throws IOException { @Test void parsesHttpQueryWithoutHost() throws IOException { MatcherAssert.assertThat( - new RqHref.Base( + new RqHrefBase( new RqFake( Arrays.asList( "GET /h?a=300", @@ -92,7 +92,7 @@ void parsesHttpQueryWithoutHost() throws IOException { void failsOnAbsentRequestLine() { Assertions.assertThrows( HttpException.class, - () -> new RqHref.Base( + () -> new RqHrefBase( new RqSimple(Collections.emptyList(), null) ).href() ); @@ -102,7 +102,7 @@ void failsOnAbsentRequestLine() { void failsOnIllegalRequestLine() { Assertions.assertThrows( HttpException.class, - () -> new RqHref.Base( + () -> new RqHrefBase( new RqFake( Arrays.asList( "GIVE/contacts", @@ -117,7 +117,7 @@ void failsOnIllegalRequestLine() { @Test void extractsParams() throws IOException { MatcherAssert.assertThat( - new RqHref.Base( + new RqHrefBase( new RqFake( Arrays.asList( "GET /hello?a=3&b=7&c&d=9%28x%29&ff", @@ -134,7 +134,7 @@ void extractsParams() throws IOException { @Test void extractsFirstParam() throws IOException { MatcherAssert.assertThat( - new RqHref.Base( + new RqHrefBase( new RqFake( Arrays.asList( "GET /hello?since=343", @@ -150,8 +150,8 @@ void extractsFirstParam() throws IOException { @Test void extractsHome() throws IOException { MatcherAssert.assertThat( - new RqHref.Smart( - new RqHref.Base( + new RqHrefSmart( + new RqHrefBase( new RqFake( Arrays.asList( "GET /bye?extra=343", @@ -168,8 +168,8 @@ void extractsHome() throws IOException { @Test void extractsHomeWithProtocol() throws IOException { MatcherAssert.assertThat( - new RqHref.Smart( - new RqHref.Base( + new RqHrefSmart( + new RqHrefBase( new RqFake( Arrays.asList( "GET /bye-dude?extra=343", @@ -187,8 +187,8 @@ void extractsHomeWithProtocol() throws IOException { @Test void extractsParamByDefault() throws IOException { MatcherAssert.assertThat( - new RqHref.Smart( - new RqHref.Base( + new RqHrefSmart( + new RqHrefBase( new RqFake( Arrays.asList( "GET /foo?present=343", diff --git a/src/test/java/org/takes/tk/TkProxyTest.java b/src/test/java/org/takes/tk/TkProxyTest.java index da8e653e6..a80fa53d8 100644 --- a/src/test/java/org/takes/tk/TkProxyTest.java +++ b/src/test/java/org/takes/tk/TkProxyTest.java @@ -44,7 +44,7 @@ import org.takes.facets.fork.TkFork; import org.takes.http.FtRemote; import org.takes.rq.RqFake; -import org.takes.rq.RqHref; +import org.takes.rq.RqHrefBase; import org.takes.rq.RqMethod; import org.takes.rq.RqPrint; import org.takes.rs.RsBodyPrint; @@ -127,7 +127,7 @@ void justWorks( void correctlyMapsPathString(final String method, final String expected) throws Exception { final Take take = req -> - new RsText(new RqHref.Base(req).href().toString()); + new RsText(new RqHrefBase(req).href().toString()); new FtRemote( new TkFork( new FkMethods(method, take)