org.jooby.Request Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of hello-world-plugin Show documentation
Show all versions of hello-world-plugin Show documentation
Kill Bill Hello World plugin
The newest version!
/**
* Apache License
* Version 2.0, January 2004
* http://www.apache.org/licenses/
*
* TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
*
* 1. Definitions.
*
* "License" shall mean the terms and conditions for use, reproduction,
* and distribution as defined by Sections 1 through 9 of this document.
*
* "Licensor" shall mean the copyright owner or entity authorized by
* the copyright owner that is granting the License.
*
* "Legal Entity" shall mean the union of the acting entity and all
* other entities that control, are controlled by, or are under common
* control with that entity. For the purposes of this definition,
* "control" means (i) the power, direct or indirect, to cause the
* direction or management of such entity, whether by contract or
* otherwise, or (ii) ownership of fifty percent (50%) or more of the
* outstanding shares, or (iii) beneficial ownership of such entity.
*
* "You" (or "Your") shall mean an individual or Legal Entity
* exercising permissions granted by this License.
*
* "Source" form shall mean the preferred form for making modifications,
* including but not limited to software source code, documentation
* source, and configuration files.
*
* "Object" form shall mean any form resulting from mechanical
* transformation or translation of a Source form, including but
* not limited to compiled object code, generated documentation,
* and conversions to other media types.
*
* "Work" shall mean the work of authorship, whether in Source or
* Object form, made available under the License, as indicated by a
* copyright notice that is included in or attached to the work
* (an example is provided in the Appendix below).
*
* "Derivative Works" shall mean any work, whether in Source or Object
* form, that is based on (or derived from) the Work and for which the
* editorial revisions, annotations, elaborations, or other modifications
* represent, as a whole, an original work of authorship. For the purposes
* of this License, Derivative Works shall not include works that remain
* separable from, or merely link (or bind by name) to the interfaces of,
* the Work and Derivative Works thereof.
*
* "Contribution" shall mean any work of authorship, including
* the original version of the Work and any modifications or additions
* to that Work or Derivative Works thereof, that is intentionally
* submitted to Licensor for inclusion in the Work by the copyright owner
* or by an individual or Legal Entity authorized to submit on behalf of
* the copyright owner. For the purposes of this definition, "submitted"
* means any form of electronic, verbal, or written communication sent
* to the Licensor or its representatives, including but not limited to
* communication on electronic mailing lists, source code control systems,
* and issue tracking systems that are managed by, or on behalf of, the
* Licensor for the purpose of discussing and improving the Work, but
* excluding communication that is conspicuously marked or otherwise
* designated in writing by the copyright owner as "Not a Contribution."
*
* "Contributor" shall mean Licensor and any individual or Legal Entity
* on behalf of whom a Contribution has been received by Licensor and
* subsequently incorporated within the Work.
*
* 2. Grant of Copyright License. Subject to the terms and conditions of
* this License, each Contributor hereby grants to You a perpetual,
* worldwide, non-exclusive, no-charge, royalty-free, irrevocable
* copyright license to reproduce, prepare Derivative Works of,
* publicly display, publicly perform, sublicense, and distribute the
* Work and such Derivative Works in Source or Object form.
*
* 3. Grant of Patent License. Subject to the terms and conditions of
* this License, each Contributor hereby grants to You a perpetual,
* worldwide, non-exclusive, no-charge, royalty-free, irrevocable
* (except as stated in this section) patent license to make, have made,
* use, offer to sell, sell, import, and otherwise transfer the Work,
* where such license applies only to those patent claims licensable
* by such Contributor that are necessarily infringed by their
* Contribution(s) alone or by combination of their Contribution(s)
* with the Work to which such Contribution(s) was submitted. If You
* institute patent litigation against any entity (including a
* cross-claim or counterclaim in a lawsuit) alleging that the Work
* or a Contribution incorporated within the Work constitutes direct
* or contributory patent infringement, then any patent licenses
* granted to You under this License for that Work shall terminate
* as of the date such litigation is filed.
*
* 4. Redistribution. You may reproduce and distribute copies of the
* Work or Derivative Works thereof in any medium, with or without
* modifications, and in Source or Object form, provided that You
* meet the following conditions:
*
* (a) You must give any other recipients of the Work or
* Derivative Works a copy of this License; and
*
* (b) You must cause any modified files to carry prominent notices
* stating that You changed the files; and
*
* (c) You must retain, in the Source form of any Derivative Works
* that You distribute, all copyright, patent, trademark, and
* attribution notices from the Source form of the Work,
* excluding those notices that do not pertain to any part of
* the Derivative Works; and
*
* (d) If the Work includes a "NOTICE" text file as part of its
* distribution, then any Derivative Works that You distribute must
* include a readable copy of the attribution notices contained
* within such NOTICE file, excluding those notices that do not
* pertain to any part of the Derivative Works, in at least one
* of the following places: within a NOTICE text file distributed
* as part of the Derivative Works; within the Source form or
* documentation, if provided along with the Derivative Works; or,
* within a display generated by the Derivative Works, if and
* wherever such third-party notices normally appear. The contents
* of the NOTICE file are for informational purposes only and
* do not modify the License. You may add Your own attribution
* notices within Derivative Works that You distribute, alongside
* or as an addendum to the NOTICE text from the Work, provided
* that such additional attribution notices cannot be construed
* as modifying the License.
*
* You may add Your own copyright statement to Your modifications and
* may provide additional or different license terms and conditions
* for use, reproduction, or distribution of Your modifications, or
* for any such Derivative Works as a whole, provided Your use,
* reproduction, and distribution of the Work otherwise complies with
* the conditions stated in this License.
*
* 5. Submission of Contributions. Unless You explicitly state otherwise,
* any Contribution intentionally submitted for inclusion in the Work
* by You to the Licensor shall be under the terms and conditions of
* this License, without any additional terms or conditions.
* Notwithstanding the above, nothing herein shall supersede or modify
* the terms of any separate license agreement you may have executed
* with Licensor regarding such Contributions.
*
* 6. Trademarks. This License does not grant permission to use the trade
* names, trademarks, service marks, or product names of the Licensor,
* except as required for reasonable and customary use in describing the
* origin of the Work and reproducing the content of the NOTICE file.
*
* 7. Disclaimer of Warranty. Unless required by applicable law or
* agreed to in writing, Licensor provides the Work (and each
* Contributor provides its Contributions) on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
* implied, including, without limitation, any warranties or conditions
* of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
* PARTICULAR PURPOSE. You are solely responsible for determining the
* appropriateness of using or redistributing the Work and assume any
* risks associated with Your exercise of permissions under this License.
*
* 8. Limitation of Liability. In no event and under no legal theory,
* whether in tort (including negligence), contract, or otherwise,
* unless required by applicable law (such as deliberate and grossly
* negligent acts) or agreed to in writing, shall any Contributor be
* liable to You for damages, including any direct, indirect, special,
* incidental, or consequential damages of any character arising as a
* result of this License or out of the use or inability to use the
* Work (including but not limited to damages for loss of goodwill,
* work stoppage, computer failure or malfunction, or any and all
* other commercial damages or losses), even if such Contributor
* has been advised of the possibility of such damages.
*
* 9. Accepting Warranty or Additional Liability. While redistributing
* the Work or Derivative Works thereof, You may choose to offer,
* and charge a fee for, acceptance of support, warranty, indemnity,
* or other liability obligations and/or rights consistent with this
* License. However, in accepting such obligations, You may act only
* on Your own behalf and on Your sole responsibility, not on behalf
* of any other Contributor, and only if You agree to indemnify,
* defend, and hold each Contributor harmless for any liability
* incurred by, or claims asserted against, such Contributor by reason
* of your accepting any such warranty or additional liability.
*
* END OF TERMS AND CONDITIONS
*
* APPENDIX: How to apply the Apache License to your work.
*
* To apply the Apache License to your work, attach the following
* boilerplate notice, with the fields enclosed by brackets "{}"
* replaced with your own identifying information. (Don't include
* the brackets!) The text should be enclosed in the appropriate
* comment syntax for the file format. We also recommend that a
* file or class name and description of purpose be included on the
* same "printed page" as the copyright notice for easier
* identification within third-party archives.
*
* Copyright 2014 Edgar Espina
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jooby;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.net.UrlEscapers;
import com.google.inject.Key;
import com.google.inject.TypeLiteral;
import static java.util.Objects.requireNonNull;
import org.jooby.scope.RequestScoped;
import javax.annotation.Nonnull;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.List;
import java.util.Locale;
import java.util.Locale.LanguageRange;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Optional;
import java.util.function.BiFunction;
/**
* Give you access at the current HTTP request in order to read parameters, headers and body.
*
* HTTP parameter and headers
*
* Access to HTTP parameter/header is available via {@link #param(String)} and
* {@link #header(String)} methods. See some examples:
*
*
*
* // str param
* String value = request.param("str").value();
*
* // optional str
* String value = request.param("str").value("defs");
*
* // int param
* int value = request.param("some").intValue();
*
* // optional int param
* Optional{@literal <}Integer{@literal >} value = request.param("some").toOptional(Integer.class);
* // list param
* List{@literal <}String{@literal >} values = request.param("some").toList(String.class);
*
*
* form post/multi-param request
*
* Due that form post are treated as HTTP params you can collect all them into a Java Object via
* {@link #params(Class)} or {@link #form(Class)} methods:
*
*
* {@code
* {
* get("/search", req -> {
* Query q = req.params(Query.class);
* });
*
* post("/person", req -> {
* Person person = req.form(Person.class);
* });
* }
* }
*
* form file upload
*
* Form post file upload are available via {@link #files(String)} or {@link #file(String)} methods:
*
* {@code
* {
* post("/upload", req -> {
* try(Upload upload = req.file("myfile")) {
* File file = upload.file();
* // work with file.
* }
* });
* }
* }
*
* @author edgar
* @since 0.1.0
*/
public interface Request extends Registry {
/**
* Flash scope.
*
* @author edgar
* @since 1.2.0
*/
interface Flash extends Map {
/**
* Keep flash cookie for next request.
*/
void keep();
}
/**
* Forwarding request.
*
* @author edgar
* @since 0.1.0
*/
class Forwarding implements Request {
/** Target request. */
private Request req;
/**
* Creates a new {@link Forwarding} request.
*
* @param request A target request.
*/
public Forwarding(final Request request) {
this.req = requireNonNull(request, "A HTTP request is required.");
}
@Override
public String path() {
return req.path();
}
@Override
public String rawPath() {
return req.rawPath();
}
@Override
public Optional queryString() {
return req.queryString();
}
@Override
public String path(final boolean escape) {
return req.path(escape);
}
@Override
public boolean matches(final String pattern) {
return req.matches(pattern);
}
@Override
public String contextPath() {
return req.contextPath();
}
@Override
public String method() {
return req.method();
}
@Override
public MediaType type() {
return req.type();
}
@Override
public List accept() {
return req.accept();
}
@Override
public Optional accepts(final List types) {
return req.accepts(types);
}
@Override
public Optional accepts(final MediaType... types) {
return req.accepts(types);
}
@Override
public Optional accepts(final String... types) {
return req.accepts(types);
}
@Override
public boolean is(final List types) {
return req.is(types);
}
@Override
public boolean is(final MediaType... types) {
return req.is(types);
}
@Override
public boolean is(final String... types) {
return req.is(types);
}
@Override
public boolean isSet(final String name) {
return req.isSet(name);
};
@Override
public Mutant params() {
return req.params();
}
@Override
public Mutant params(final String... xss) {
return req.params(xss);
}
@Override
public T params(final Class type) {
return req.params(type);
}
@Override
public T params(final Class type, final String... xss) {
return req.params(type, xss);
}
@Override
public Mutant param(final String name) {
return req.param(name);
}
@Override
public Mutant param(final String name, final String... xss) {
return req.param(name, xss);
}
@Override
public Upload file(final String name) throws IOException {
return req.file(name);
}
@Override
public List files(final String name) throws IOException {
return req.files(name);
}
@Override
public Mutant header(final String name) {
return req.header(name);
}
@Override
public Mutant header(final String name, final String... xss) {
return req.header(name, xss);
}
@Override
public Map headers() {
return req.headers();
}
@Override
public Mutant cookie(final String name) {
return req.cookie(name);
}
@Override
public List cookies() {
return req.cookies();
}
@Override
public Mutant body() throws Exception {
return req.body();
}
@Override
public T body(final Class type) throws Exception {
return req.body(type);
}
@Override
public T require(final Class type) {
return req.require(type);
}
@Override
public T require(final TypeLiteral type) {
return req.require(type);
}
@Override
public T require(final Key key) {
return req.require(key);
}
@Override
public Charset charset() {
return req.charset();
}
@Override
public long length() {
return req.length();
}
@Override
public Locale locale() {
return req.locale();
}
@Override
public Locale locale(final BiFunction, List, Locale> filter) {
return req.locale(filter);
}
@Override
public List locales(
final BiFunction, List, List> filter) {
return req.locales(filter);
}
@Override
public List locales() {
return req.locales();
}
@Override
public String ip() {
return req.ip();
}
@Override
public int port() {
return req.port();
}
@Override
public Route route() {
return req.route();
}
@Override
public Session session() {
return req.session();
}
@Override
public Optional ifSession() {
return req.ifSession();
}
@Override
public String hostname() {
return req.hostname();
}
@Override
public String protocol() {
return req.protocol();
}
@Override
public boolean secure() {
return req.secure();
}
@Override
public boolean xhr() {
return req.xhr();
}
@Override
public Map attributes() {
return req.attributes();
}
@Override
public Optional ifGet(final String name) {
return req.ifGet(name);
}
@Override
public T get(final String name) {
return req.get(name);
}
@Override
public T get(final String name, final T def) {
return req.get(name, def);
}
@Override
public Request set(final String name, final Object value) {
req.set(name, value);
return this;
}
@Override
public Request set(final Key> key, final Object value) {
req.set(key, value);
return this;
}
@Override
public Request set(final Class> type, final Object value) {
req.set(type, value);
return this;
}
@Override
public Request set(final TypeLiteral> type, final Object value) {
req.set(type, value);
return this;
}
@Override
public Optional unset(final String name) {
return req.unset(name);
}
@Override
public Flash flash() throws NoSuchElementException {
return req.flash();
}
@Override
public String flash(final String name) throws NoSuchElementException {
return req.flash(name);
}
@Override
public Request flash(final String name, final Object value) {
req.flash(name, value);
return this;
}
@Override
public Optional ifFlash(final String name) {
return req.ifFlash(name);
}
@Override
public Request push(final String path) {
req.push(path);
return this;
}
@Override
public Request push(final String path, final Map headers) {
req.push(path, headers);
return this;
}
@Override
public long timestamp() {
return req.timestamp();
}
@Override
public String toString() {
return req.toString();
}
/**
* Unwrap a request in order to find out the target instance.
*
* @param req A request.
* @return A target instance (not a {@link Forwarding}).
*/
public static Request unwrap(final Request req) {
requireNonNull(req, "A request is required.");
Request root = req;
while (root instanceof Forwarding) {
root = ((Forwarding) root).req;
}
return root;
}
}
/**
* Given:
*
*
* http://domain.com/some/path.html {@literal ->} /some/path.html
* http://domain.com/a.html {@literal ->} /a.html
*
*
* @return The request URL pathname.
*/
@Nonnull
default String path() {
return path(false);
}
/**
* Raw path, like {@link #path()} but without decoding.
*
* @return Raw path, like {@link #path()} but without decoding.
*/
@Nonnull
String rawPath();
/**
* The query string, without the leading ?
.
*
* @return The query string, without the leading ?
.
*/
@Nonnull
Optional queryString();
/**
* Escape the path using {@link UrlEscapers#urlFragmentEscaper()}.
*
* Given:
*
* {@code
* http://domain.com/404X
{@literal ->} /404%3Ch1%3EX%3C/h1%3E
* }
*
* @param escape True if we want to escape this path.
* @return The request URL pathname.
*/
@Nonnull
default String path(final boolean escape) {
String path = route().path();
return escape ? UrlEscapers.urlFragmentEscaper().escape(path) : path;
}
/**
* Application path (a.k.a context path). It is the value defined by:
* application.path
. Default is: /
*
* This method returns empty string for /
. Otherwise, it is identical the value of
* application.path
.
*
* @return Application context path..
*/
@Nonnull
String contextPath();
/**
* @return HTTP method.
*/
@Nonnull
default String method() {
return route().method();
}
/**
* @return The Content-Type
header. Default is: {@literal*}/{@literal*}.
*/
@Nonnull
MediaType type();
/**
* @return The value of the Accept header
. Default is: {@literal*}/{@literal*}.
*/
@Nonnull
List accept();
/**
* Check if the given types are acceptable, returning the best match when true, or else
* Optional.empty.
*
*
* // Accept: text/html
* req.accepts("text/html");
* // {@literal =>} "text/html"
*
* // Accept: text/*, application/json
* req.accepts("text/html");
* // {@literal =>} "text/html"
* req.accepts("text/html");
* // {@literal =>} "text/html"
* req.accepts("application/json" "text/plain");
* // {@literal =>} "application/json"
* req.accepts("application/json");
* // {@literal =>} "application/json"
*
* // Accept: text/*, application/json
* req.accepts("image/png");
* // {@literal =>} Optional.empty
*
* // Accept: text/*;q=.5, application/json
* req.accepts("text/html", "application/json");
* // {@literal =>} "application/json"
*
*
* @param types Types to test.
* @return The best acceptable type.
*/
@Nonnull
default Optional accepts(final String... types) {
return accepts(MediaType.valueOf(types));
}
/**
* Test if the given request path matches the pattern.
*
* @param pattern A pattern to test for.
* @return True, if the request path matches the pattern.
*/
boolean matches(String pattern);
/**
* True, if request accept any of the given types.
*
* @param types Types to test
* @return True if any of the given type is accepted.
*/
default boolean is(final String... types) {
return accepts(types).isPresent();
}
/**
* True, if request accept any of the given types.
*
* @param types Types to test
* @return True if any of the given type is accepted.
*/
default boolean is(final MediaType... types) {
return accepts(types).isPresent();
}
/**
* True, if request accept any of the given types.
*
* @param types Types to test
* @return True if any of the given type is accepted.
*/
default boolean is(final List types) {
return accepts(types).isPresent();
}
/**
* Check if the given types are acceptable, returning the best match when true, or else
* Optional.empty.
*
*
* // Accept: text/html
* req.accepts("text/html");
* // {@literal =>} "text/html"
*
* // Accept: text/*, application/json
* req.accepts("text/html");
* // {@literal =>} "text/html"
* req.accepts("text/html");
* // {@literal =>} "text/html"
* req.accepts("application/json" "text/plain");
* // {@literal =>} "application/json"
* req.accepts("application/json");
* // {@literal =>} "application/json"
*
* // Accept: text/*, application/json
* req.accepts("image/png");
* // {@literal =>} Optional.empty
*
* // Accept: text/*;q=.5, application/json
* req.accepts("text/html", "application/json");
* // {@literal =>} "application/json"
*
*
* @param types Types to test.
* @return The best acceptable type.
*/
@Nonnull
default Optional accepts(final MediaType... types) {
return accepts(ImmutableList.copyOf(types));
}
/**
* Check if the given types are acceptable, returning the best match when true, or else
* Optional.empty.
*
*
* // Accept: text/html
* req.accepts("text/html");
* // {@literal =>} "text/html"
*
* // Accept: text/*, application/json
* req.accepts("text/html");
* // {@literal =>} "text/html"
* req.accepts("text/html");
* // {@literal =>} "text/html"
* req.accepts("application/json" "text/plain");
* // {@literal =>} "application/json"
* req.accepts("application/json");
* // {@literal =>} "application/json"
*
* // Accept: text/*, application/json
* req.accepts("image/png");
* // {@literal =>} Optional.empty
*
* // Accept: text/*;q=.5, application/json
* req.accepts("text/html", "application/json");
* // {@literal =>} "application/json"
*
*
* @param types Types to test for.
* @return The best acceptable type.
*/
@Nonnull
Optional accepts(List types);
/**
* Get all the available parameters. A HTTP parameter can be provided in any of
* these forms:
*
*
* - Path parameter, like:
/path/:name
or /path/{name}
* - Query parameter, like:
?name=jooby
* - Body parameter when
Content-Type
is
* application/x-www-form-urlencoded
or multipart/form-data
*
*
* @return All the parameters.
*/
@Nonnull
Mutant params();
/**
* Get all the available parameters. A HTTP parameter can be provided in any of
* these forms:
*
*
* - Path parameter, like:
/path/:name
or /path/{name}
* - Query parameter, like:
?name=jooby
* - Body parameter when
Content-Type
is
* application/x-www-form-urlencoded
or multipart/form-data
*
*
* @param xss Xss filter to apply.
* @return All the parameters.
*/
@Nonnull
Mutant params(String... xss);
/**
* Short version of params().to(type)
.
*
* @param type Object type.
* @param Value type.
* @return Instance of object.
*/
@Nonnull
default T params(final Class type) {
return params().to(type);
}
/**
* Short version of params().to(type)
.
*
* @param type Object type.
* @param Value type.
* @return Instance of object.
*/
@Nonnull
default T form(final Class type) {
return params().to(type);
}
/**
* Short version of params(xss).to(type)
.
*
* @param type Object type.
* @param xss Xss filter to apply.
* @param Value type.
* @return Instance of object.
*/
@Nonnull
default T params(final Class type, final String... xss) {
return params(xss).to(type);
}
/**
* Short version of params(xss).to(type)
.
*
* @param type Object type.
* @param xss Xss filter to apply.
* @param Value type.
* @return Instance of object.
*/
@Nonnull
default T form(final Class type, final String... xss) {
return params(xss).to(type);
}
/**
* Get a HTTP request parameter under the given name. A HTTP parameter can be provided in any of
* these forms:
*
* - Path parameter, like:
/path/:name
or /path/{name}
* - Query parameter, like:
?name=jooby
* - Body parameter when
Content-Type
is
* application/x-www-form-urlencoded
or multipart/form-data
*
*
* The order of precedence is: path
, query
and body
. For
* example a pattern like: GET /path/:name
for /path/jooby?name=rocks
* produces:
*
*
* assertEquals("jooby", req.param(name).value());
*
* assertEquals("jooby", req.param(name).toList().get(0));
* assertEquals("rocks", req.param(name).toList().get(1));
*
*
* Uploads can be retrieved too when Content-Type
is multipart/form-data
* see {@link Upload} for more information.
*
* @param name A parameter's name.
* @return A HTTP request parameter.
*/
@Nonnull
Mutant param(String name);
/**
* Get a HTTP request parameter under the given name. A HTTP parameter can be provided in any of
* these forms:
*
* - Path parameter, like:
/path/:name
or /path/{name}
* - Query parameter, like:
?name=jooby
* - Body parameter when
Content-Type
is
* application/x-www-form-urlencoded
or multipart/form-data
*
*
* The order of precedence is: path
, query
and body
. For
* example a pattern like: GET /path/:name
for /path/jooby?name=rocks
* produces:
*
*
* assertEquals("jooby", req.param(name).value());
*
* assertEquals("jooby", req.param(name).toList().get(0));
* assertEquals("rocks", req.param(name).toList().get(1));
*
*
* Uploads can be retrieved too when Content-Type
is multipart/form-data
* see {@link Upload} for more information.
*
* @param name A parameter's name.
* @param xss Xss filter to apply.
* @return A HTTP request parameter.
*/
@Nonnull
Mutant param(String name, String... xss);
/**
* Get a file {@link Upload} with the given name. The request must be a POST with
* multipart/form-data
content-type.
*
* @param name File's name.
* @return An {@link Upload}.
* @throws IOException
*/
@Nonnull
default Upload file(final String name) throws IOException {
List files = files(name);
if (files.size() == 0) {
throw new Err.Missing(name);
}
return files.get(0);
}
/**
* Get a file {@link Upload} with the given name or empty. The request must be a POST with
* multipart/form-data
content-type.
*
* @param name File's name.
* @return An {@link Upload}.
* @throws IOException
*/
@Nonnull
default Optional ifFile(final String name) throws IOException {
List files = files(name);
return files.size() == 0 ? Optional.empty() : Optional.of(files.get(0));
}
/**
* Get a list of file {@link Upload} with the given name. The request must be a POST with
* multipart/form-data
content-type.
*
* @param name File's name.
* @return A list of {@link Upload}.
* @throws IOException
*/
@Nonnull
List files(final String name) throws IOException;
/**
* Get a HTTP header.
*
* @param name A header's name.
* @return A HTTP request header.
*/
@Nonnull
Mutant header(String name);
/**
* Get a HTTP header and apply the XSS escapers.
*
* @param name A header's name.
* @param xss Xss escapers.
* @return A HTTP request header.
*/
@Nonnull
Mutant header(final String name, final String... xss);
/**
* @return All the headers.
*/
@Nonnull
Map headers();
/**
* Get a cookie with the given name (if present).
*
* @param name Cookie's name.
* @return A cookie or an empty optional.
*/
@Nonnull
Mutant cookie(String name);
/**
* @return All the cookies.
*/
@Nonnull
List cookies();
/**
* HTTP body. Please don't use this method for form submits. This method is used for getting
* raw
data or a data like json, xml, etc...
*
* @return The HTTP body.
* @throws Exception If body can't be converted or there is no HTTP body.
*/
@Nonnull
Mutant body() throws Exception;
/**
* Short version of body().to(type)
.
*
* HTTP body. Please don't use this method for form submits. This method is used for getting
* raw
or a parsed data like json, xml, etc...
*
* @param type Object type.
* @param Value type.
* @return Instance of object.
* @throws Exception If body can't be converted or there is no HTTP body.
*/
@Nonnull
default T body(final Class type) throws Exception {
return body().to(type);
}
/**
* The charset defined in the request body. If the request doesn't specify a character
* encoding, this method return the global charset: application.charset
.
*
* @return A current charset.
*/
@Nonnull
Charset charset();
/**
* Get a list of locale that best matches the current request as per {@link Locale#filter}.
*
* @return A list of matching locales or empty list.
*/
@Nonnull
default List locales() {
return locales(Locale::filter);
}
/**
* Get a list of locale that best matches the current request.
*
* The first filter argument is the value of Accept-Language
as
* {@link Locale.LanguageRange} and filter while the second argument is a list of supported
* locales defined by the application.lang
property.
*
* The next example returns a list of matching {@code Locale} instances using the filtering
* mechanism defined in RFC 4647:
*
* {@code
* req.locales(Locale::filter)
* }
*
* @param filter A locale filter.
* @return A list of matching locales.
*/
@Nonnull
List locales(BiFunction, List, List> filter);
/**
* Get a locale that best matches the current request.
*
* The first filter argument is the value of Accept-Language
as
* {@link Locale.LanguageRange} and filter while the second argument is a list of supported
* locales defined by the application.lang
property.
*
* The next example returns a {@code Locale} instance for the best-matching language
* tag using the lookup mechanism defined in RFC 4647.
*
* {@code
* req.locale(Locale::lookup)
* }
*
* @param filter A locale filter.
* @return A matching locale.
*/
@Nonnull
Locale locale(BiFunction, List, Locale> filter);
/**
* Get a locale that best matches the current request or the default locale as specified
* in application.lang
.
*
* @return A matching locale.
*/
@Nonnull
default Locale locale() {
return locale((priorityList, locales) -> Optional.ofNullable(Locale.lookup(priorityList, locales))
.orElse(locales.get(0)));
}
/**
* @return The length, in bytes, of the request body and made available by the input stream, or
* -1
if the length is not known.
*/
long length();
/**
* @return The IP address of the client or last proxy that sent the request.
*/
@Nonnull
String ip();
/**
* @return Server port, from host
header or the server port where the client
* connection was accepted on.
*/
int port();
/**
* @return The currently matched {@link Route}.
*/
@Nonnull
Route route();
/**
* The fully qualified name of the resource being requested, as obtained from the Host HTTP
* header.
*
* @return The fully qualified name of the server.
*/
@Nonnull
String hostname();
/**
* @return The current session associated with this request or if the request does not have a
* session, creates one.
*/
@Nonnull
Session session();
/**
* @return The current session associated with this request if there is one.
*/
@Nonnull
Optional ifSession();
/**
* @return True if the X-Requested-With
header is set to XMLHttpRequest
.
*/
default boolean xhr() {
return header("X-Requested-With")
.toOptional(String.class)
.map("XMLHttpRequest"::equalsIgnoreCase)
.orElse(Boolean.FALSE);
}
/**
* @return The name and version of the protocol the request uses in the form
* protocol/majorVersion.minorVersion, for example, HTTP/1.1
*/
@Nonnull
String protocol();
/**
* @return True if this request was made using a secure channel, such as HTTPS.
*/
boolean secure();
/**
* Set local attribute.
*
* @param name Attribute's name.
* @param value Attribute's local. NOT null.
* @return This request.
*/
@Nonnull
Request set(String name, Object value);
/**
* Give you access to flash scope. Usage:
*
* {@code
* {
* use(new FlashScope());
*
* get("/", req -> {
* Map flash = req.flash();
* return flash;
* });
* }
* }
*
* As you can see in the example above, the {@link FlashScope} needs to be install it by calling
* {@link Jooby#use(org.jooby.Jooby.Module)} otherwise a call to this method ends in
* {@link Err BAD_REQUEST}.
*
* @return A mutable map with attributes from {@link FlashScope}.
* @throws Err Bad request error if the {@link FlashScope} was not installed it.
*/
@Nonnull
default Flash flash() throws Err {
Optional flash = ifGet(FlashScope.NAME);
return flash.orElseThrow(() -> new Err(Status.BAD_REQUEST,
"Flash scope isn't available. Install via: use(new FlashScope());"));
}
/**
* Set a flash attribute. Flash scope attributes are accessible from template engines, by
* prefixing attributes with flash.
. For example a call to
* flash("success", "OK")
is accessible from template engines using
* flash.success
*
* @param name Attribute's name.
* @param value Attribute's value.
* @return This request.
*/
@Nonnull
default Request flash(final String name, final Object value) {
requireNonNull(name, "Attribute's name is required.");
Map flash = flash();
if (value == null) {
flash.remove(name);
} else {
flash.put(name, value.toString());
}
return this;
}
/**
* Get an optional for the given flash attribute's name.
*
* @param name Attribute's name.
* @return Optional flash attribute.
*/
@Nonnull
default Optional ifFlash(final String name) {
return Optional.ofNullable(flash().get(name));
}
/**
* Get a flash attribute value or throws {@link Err BAD_REQUEST error} if missing.
*
* @param name Attribute's name.
* @return Flash attribute.
* @throws Err Bad request error if flash attribute is missing.
*/
@Nonnull
default String flash(final String name) throws Err {
return ifFlash(name)
.orElseThrow(() -> new Err(Status.BAD_REQUEST,
"Required flash attribute: '" + name + "' is not present"));
}
/**
* @param name Attribute's name.
* @return True if the local attribute is set.
*/
default boolean isSet(final String name) {
return ifGet(name).isPresent();
}
/**
* Get a request local attribute.
*
* @param name Attribute's name.
* @param Target type.
* @return A local attribute.
*/
@Nonnull
Optional ifGet(String name);
/**
* Get a request local attribute.
*
* @param name Attribute's name.
* @param def A default value.
* @param Target type.
* @return A local attribute.
*/
@Nonnull
default T get(final String name, final T def) {
Optional opt = ifGet(name);
return opt.orElse(def);
}
/**
* Get a request local attribute.
*
* @param name Attribute's name.
* @param Target type.
* @return A local attribute.
* @throws Err with {@link Status#BAD_REQUEST}.
*/
@Nonnull
default T get(final String name) {
Optional opt = ifGet(name);
return opt.orElseThrow(
() -> new Err(Status.BAD_REQUEST, "Required local attribute: " + name + " is not present"));
}
/**
* Remove a request local attribute.
*
* @param name Attribute's name.
* @param Target type.
* @return A local attribute.
*/
@Nonnull
Optional unset(String name);
/**
* A read only version of the current locals.
*
* @return Attributes locals.
*/
@Nonnull
Map attributes();
/**
* Seed a {@link RequestScoped} object.
*
* @param type Object type.
* @param value Actual object to bind.
* @return Current request.
*/
@Nonnull
default Request set(final Class> type, final Object value) {
return set(TypeLiteral.get(type), value);
}
/**
* Seed a {@link RequestScoped} object.
*
* @param type Seed type.
* @param value Actual object to bind.
* @return Current request.
*/
@Nonnull
default Request set(final TypeLiteral> type, final Object value) {
return set(Key.get(type), value);
}
/**
* Seed a {@link RequestScoped} object.
*
* @param key Seed key.
* @param value Actual object to bind.
* @return Current request.
*/
@Nonnull
Request set(Key> key, Object value);
/**
* Send a push promise frame to the client and push the resource identified by the given path.
*
* @param path Path of the resource to push.
* @return This request.
*/
@Nonnull
default Request push(final String path) {
return push(path, ImmutableMap.of());
}
/**
* Send a push promise frame to the client and push the resource identified by the given path.
*
* @param path Path of the resource to push.
* @param headers Headers to send.
* @return This request.
*/
@Nonnull
Request push(final String path, final Map headers);
/**
* Request timestamp.
*
* @return The time that the request was received.
*/
long timestamp();
}