All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.vertx.core.http.HttpServerRequest Maven / Gradle / Ivy

There is a newer version: 5.0.0.CR1
Show newest version
/*
 * Copyright (c) 2011-2019 Contributors to the Eclipse Foundation
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License 2.0 which is available at
 * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
 * which is available at https://www.apache.org/licenses/LICENSE-2.0.
 *
 * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
 */

package io.vertx.core.http;

import io.netty.handler.codec.DecoderResult;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.TooLongHttpHeaderException;
import io.netty.handler.codec.http.TooLongHttpLineException;
import io.vertx.codegen.annotations.*;
import io.vertx.core.AsyncResult;
import io.vertx.core.Future;
import io.vertx.core.Handler;
import io.vertx.core.MultiMap;
import io.vertx.core.buffer.Buffer;
import io.vertx.core.net.HostAndPort;
import io.vertx.core.net.NetSocket;
import io.vertx.core.net.SocketAddress;
import io.vertx.core.streams.ReadStream;

import javax.net.ssl.SSLPeerUnverifiedException;
import javax.net.ssl.SSLSession;
import javax.security.cert.X509Certificate;
import java.util.*;
import java.util.stream.Collectors;

/**
 * Represents a server-side HTTP request.
 * 

* Instances are created for each request and passed to the user via a handler. *

* Each instance of this class is associated with a corresponding {@link HttpServerResponse} instance via * {@link #response}.

* It implements {@link io.vertx.core.streams.ReadStream} so it can be used with * {@link io.vertx.core.streams.Pipe} to pipe data with flow control. *

* * @author Tim Fox */ @VertxGen public interface HttpServerRequest extends ReadStream { /** * The default invalid request handler, it uses the {@link #decoderResult()} cause and the request information * to determine the status code of the response to be sent. * *

    *
  • When the cause is an instance of {@code io.netty.handler.codec.TooLongFrameException} and the error message * starts with An HTTP line is larger than the {@code REQUEST_URI_TOO_LONG} status is sent
  • *
  • Otherwise when the cause is an instance of {@code io.netty.handler.codec.TooLongFrameException} and the error message * starts with HTTP header is larger than the {@code REQUEST_HEADER_FIELDS_TOO_LARGE} status is sent
  • *
  • Otherwise then {@code BAD_REQUEST} status is sent
  • *
*/ @GenIgnore Handler DEFAULT_INVALID_REQUEST_HANDLER = request -> { DecoderResult result = request.decoderResult(); Throwable cause = result.cause(); HttpResponseStatus status = null; if (cause instanceof TooLongHttpLineException) { status = HttpResponseStatus.REQUEST_URI_TOO_LONG; } else if (cause instanceof TooLongHttpHeaderException) { status = HttpResponseStatus.REQUEST_HEADER_FIELDS_TOO_LARGE; } if (status == null) { status = HttpResponseStatus.BAD_REQUEST; } HttpServerResponse response = request.response(); response.setStatusCode(status.code()).end(); response.close(); }; @Override HttpServerRequest exceptionHandler(Handler handler); @Override HttpServerRequest handler(Handler handler); @Override HttpServerRequest pause(); @Override HttpServerRequest resume(); @Override HttpServerRequest fetch(long amount); @Override HttpServerRequest endHandler(Handler endHandler); /** * @return the HTTP version of the request */ HttpVersion version(); /** * @return the HTTP method for the request. */ HttpMethod method(); /** * @return true if this {@link io.vertx.core.net.NetSocket} is encrypted via SSL/TLS */ default boolean isSSL() { return connection().isSsl(); } /** * @return the scheme of the request */ @Nullable String scheme(); /** * @return the URI of the request. This is usually a relative URI */ String uri(); /** * @return The path part of the uri. For example /somepath/somemorepath/someresource.foo */ @Nullable String path(); /** * @return the query part of the uri. For example someparam=32&someotherparam=x */ @Nullable String query(); /** * @return the request authority. For HTTP/2 the {@literal :authority} pseudo header is returned, for HTTP/1.x the * {@literal Host} header is returned or {@code null} when no such header is present. When the authority * string does not carry a port, the {@link HostAndPort#port()} returns {@code -1} to indicate the * scheme port is prevalent. */ @Nullable HostAndPort authority(); /** * @return the request host. For HTTP2 it returns the {@literal :authority} pseudo header otherwise it returns the {@literal Host} header * @deprecated instead use {@link #authority()} */ @Deprecated @Nullable String host(); /** * @return the total number of bytes read for the body of the request. */ long bytesRead(); /** * @return the response. Each instance of this class has an {@link HttpServerResponse} instance attached to it. This is used * to send the response back to the client. */ @CacheReturn HttpServerResponse response(); /** * @return the headers in the request. */ @CacheReturn MultiMap headers(); /** * Return the first header value with the specified name * * @param headerName the header name * @return the header value */ @Nullable default String getHeader(String headerName) { return headers().get(headerName); } /** * Return the first header value with the specified name * * @param headerName the header name * @return the header value */ @GenIgnore(GenIgnore.PERMITTED_TYPE) default String getHeader(CharSequence headerName) { return headers().get(headerName); } /** * Override the charset to use for decoding the query parameter map, when none is set, {@code UTF8} is used. * * @param charset the charset to use for decoding query params * @return a reference to this, so the API can be used fluently */ @Fluent HttpServerRequest setParamsCharset(String charset); /** * @return the charset used for decoding query parameters */ String getParamsCharset(); /** * @return the query parameters in the request */ @CacheReturn MultiMap params(); /** * Return the first param value with the specified name * * @param paramName the param name * @return the param value */ @Nullable default String getParam(String paramName) { return params().get(paramName); } /** * Return the first param value with the specified name or {@code defaultValue} when the query param is not present * * @param paramName the param name * @param defaultValue the default value, must be non-null * @return the param value or {@code defaultValue} when not present */ default String getParam(String paramName, String defaultValue) { Objects.requireNonNull(defaultValue, "defaultValue"); final String paramValue = params().get(paramName); return paramValue != null ? paramValue : defaultValue; } /** * @return the remote address for this connection, possibly {@code null} (e.g a server bound on a domain socket). * If {@code useProxyProtocol} is set to {@code true}, the address returned will be of the actual connecting client. */ @CacheReturn default SocketAddress remoteAddress() { return connection().remoteAddress(); } /** * @return the local address for this connection, possibly {@code null} (e.g a server bound on a domain socket) * If {@code useProxyProtocol} is set to {@code true}, the address returned will be of the proxy. */ @CacheReturn default SocketAddress localAddress() { return connection().localAddress(); } /** * @return SSLSession associated with the underlying socket. Returns null if connection is * not SSL. * @see javax.net.ssl.SSLSession */ @GenIgnore(GenIgnore.PERMITTED_TYPE) default SSLSession sslSession() { return connection().sslSession(); } /** * Note: Java SE 5+ recommends to use javax.net.ssl.SSLSession#getPeerCertificates() instead of * of javax.net.ssl.SSLSession#getPeerCertificateChain() which this method is based on. Use {@link #sslSession()} to * access that method. * * @return an ordered array of the peer certificates. Returns null if connection is * not SSL. * @throws javax.net.ssl.SSLPeerUnverifiedException SSL peer's identity has not been verified. * @see javax.net.ssl.SSLSession#getPeerCertificateChain() * @see #sslSession() */ @GenIgnore X509Certificate[] peerCertificateChain() throws SSLPeerUnverifiedException; /** * @return the absolute URI corresponding to the HTTP request */ String absoluteURI(); /** * Convenience method for receiving the entire request body in one piece. *

* This saves the user having to manually setting a data and end handler and append the chunks of the body until * the whole body received. Don't use this if your request body is large - you could potentially run out of RAM. * * @param bodyHandler This handler will be called after all the body has been received */ @Fluent default HttpServerRequest bodyHandler(@Nullable Handler bodyHandler) { body().onSuccess(bodyHandler); return this; } /** * Same as {@link #body()} but with an {@code handler} called when the operation completes */ default HttpServerRequest body(Handler> handler) { body().onComplete(handler); return this; } /** * Convenience method for receiving the entire request body in one piece. *

* This saves you having to manually set a dataHandler and an endHandler and append the chunks of the body until * the whole body received. Don't use this if your request body is large - you could potentially run out of RAM. * * @return a future completed with the body result */ Future body(); /** * Same as {@link #end()} but with an {@code handler} called when the operation completes */ default void end(Handler> handler) { end().onComplete(handler); } /** * Returns a future signaling when the request has been fully received successfully or failed. * * @return a future completed with the body result */ Future end(); /** * Establish a TCP tunnel with the client. * *

This must be called only for {@code CONNECT} HTTP method or for HTTP connection upgrade, before any response is sent. * *

Calling this sends a {@code 200} response for a {@code CONNECT} or a {@code 101} for a connection upgrade wit * no {@code content-length} header set and then provides the {@code NetSocket} for handling the created tunnel. * Any HTTP header set on the response before calling this method will be sent. * *

   * server.requestHandler(req -> {
   *   if (req.method() == HttpMethod.CONNECT) {
   *     // Send a 200 response to accept the connect
   *     NetSocket socket = req.netSocket();
   *     socket.handler(buff -> {
   *       socket.write(buff);
   *     });
   *   }
   *   ...
   * });
   * 
* * @param handler the completion handler */ default void toNetSocket(Handler> handler) { Future fut = toNetSocket(); if (handler != null) { fut.onComplete(handler); } } /** * Like {@link #toNetSocket(Handler)} but returns a {@code Future} of the asynchronous result */ Future toNetSocket(); /** * Call this with true if you are expecting a multi-part body to be submitted in the request. * This must be called before the body of the request has been received * * @param expect true - if you are expecting a multi-part body * @return a reference to this, so the API can be used fluently */ @Fluent HttpServerRequest setExpectMultipart(boolean expect); /** * @return true if we are expecting a multi-part body for this request. See {@link #setExpectMultipart}. */ boolean isExpectMultipart(); /** * Set an upload handler. The handler will get notified once a new file upload was received to allow you to deal * with the file upload. * * @return a reference to this, so the API can be used fluently */ @Fluent HttpServerRequest uploadHandler(@Nullable Handler uploadHandler); /** * Returns a map of all form attributes in the request. *

* Be aware that the attributes will only be available after the whole body has been received, i.e. after * the request end handler has been called. *

* {@link #setExpectMultipart(boolean)} must be called first before trying to get the form attributes. * * @return the form attributes */ @CacheReturn MultiMap formAttributes(); /** * Return the first form attribute value with the specified name * * @param attributeName the attribute name * @return the attribute value */ @Nullable String getFormAttribute(String attributeName); /** * @return the id of the stream of this request, {@literal -1} when it is not yet determined, i.e * the request has not been yet sent or it is not supported HTTP/1.x */ @CacheReturn default int streamId() { return -1; } /** * Upgrade the connection of the current request to a WebSocket. *

* This is an alternative way of handling WebSockets and can only be used if no WebSocket handler is set on the * {@code HttpServer}, and can only be used during the upgrade request during the WebSocket handshake. * *

Both {@link #handler(Handler)} and {@link #endHandler(Handler)} will be set to get the full body of the * request that is necessary to perform the WebSocket handshake. * *

If you need to do an asynchronous upgrade, i.e not performed immediately in your request handler, * you need to {@link #pause()} the request in order to not lose HTTP events necessary to upgrade the * request. * * @param handler the completion handler */ default void toWebSocket(Handler> handler) { Future fut = toWebSocket(); if (handler != null) { fut.onComplete(handler); } } /** * Like {@link #toWebSocket(Handler)} but returns a {@code Future} of the asynchronous result */ Future toWebSocket(); /** * Has the request ended? I.e. has the entire request, including the body been read? * * @return true if ended */ boolean isEnded(); /** * Set a custom frame handler. The handler will get notified when the http stream receives an custom HTTP/2 * frame. HTTP/2 permits extension of the protocol. * * @return a reference to this, so the API can be used fluently */ @Fluent HttpServerRequest customFrameHandler(Handler handler); /** * @return the {@link HttpConnection} associated with this request */ @CacheReturn HttpConnection connection(); /** * @return the priority of the associated HTTP/2 stream for HTTP/2 otherwise {@code null} */ default StreamPriority streamPriority() { return null; } /** * Set an handler for stream priority changes *

* This is not implemented for HTTP/1.x. * * @param handler the handler to be called when stream priority changes */ @Fluent HttpServerRequest streamPriorityHandler(Handler handler); /** * @return Netty's decoder result useful for handling invalid requests with {@link HttpServer#invalidRequestHandler} */ @GenIgnore DecoderResult decoderResult(); /** * Get the cookie with the specified name. * * NOTE: this will return just the 1st {@link Cookie} that matches the given name, to get all cookies for this name * see: {@link #cookies(String)} * * @param name the cookie name * @return the cookie or {@code null} if not found. */ @Nullable Cookie getCookie(String name); /** * Get the cookie with the specified {@code }. * * @param name the cookie name * @param domain the cookie domain * @param path the cookie path * @return the cookie or {@code null} if not found. */ @Nullable Cookie getCookie(String name, String domain, String path); /** * @return the number of cookies in the cookie jar. */ default int cookieCount() { return cookies().size(); } /** * @deprecated the implementation made a wrong assumption that cookies could be identified only by their name. The RFC * states that the tuple of {@code } is the unique identifier. * * When more than one cookie has the same name, the map will hold that lost one to be parsed and any previously parsed * value will be silently overwritten. * * @return a map of all the cookies. */ @Deprecated default Map cookieMap() { return cookies() .stream() .collect(Collectors.toMap(Cookie::getName, cookie -> cookie)); } /** * Returns a read only set of parsed cookies that match the given name, or an empty set. Several cookies may share the * same name but have different keys. A cookie is unique by its {@code } tuple. * * The set entries are references to the request original set. This means that performing property changes in the * cookie objects will affect the original object too. * * NOTE: the returned {@link Set} is read-only. This means any attempt to modify (add or remove to the set), will * throw {@link UnsupportedOperationException}. * * @param name the name to be matches * @return the matching cookies or empty set */ Set cookies(String name); /** * Returns a modifiable set of parsed cookies from the {@code COOKIE} header. Several cookies may share the * same name but have different keys. A cookie is unique by its {@code } tuple. * * Request cookies are directly linked to response cookies. Any modification to a cookie object in the returned set * will mark the cookie to be included in the HTTP response. Removing a cookie from the set, will also mean that it * will be removed from the response, regardless if it was modified or not. * * @return a set with all cookies in the cookie jar. */ Set cookies(); /** * Marks this request as being routed to the given route. This is purely informational and is * being provided to metrics. * * @param route The route this request has been routed to. */ @Fluent default HttpServerRequest routed(String route) { return this; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy