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

io.undertow.server.protocol.http.HttpContinue Maven / Gradle / Ivy

Go to download

This artifact provides a single jar that contains all classes required to use remote Jakarta Enterprise Beans and Jakarta Messaging, including all dependencies. It is intended for use by those not using maven, maven users should just import the Jakarta Enterprise Beans and Jakarta Messaging BOM's instead (shaded JAR's cause lots of problems with maven, as it is very easy to inadvertently end up with different versions on classes on the class path).

The newest version!
/*
 * JBoss, Home of Professional Open Source.
 * Copyright 2014 Red Hat, Inc., and individual contributors
 * as indicated by the @author tags.
 *
 * 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 io.undertow.server.protocol.http;

import java.io.IOException;
import java.nio.channels.Channel;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;

import org.xnio.ChannelExceptionHandler;
import org.xnio.ChannelListener;
import org.xnio.ChannelListeners;
import org.xnio.channels.StreamSinkChannel;
import io.undertow.UndertowMessages;
import io.undertow.io.IoCallback;
import io.undertow.server.HttpHandler;
import io.undertow.server.HttpServerExchange;
import io.undertow.util.AttachmentKey;
import io.undertow.util.HeaderMap;
import io.undertow.util.Headers;
import io.undertow.util.HttpString;
import io.undertow.util.Protocols;
import io.undertow.util.StatusCodes;

/**
 * Class that provides support for dealing with HTTP 100 (Continue) responses.
 * 

* Note that if a client is pipelining some requests and sending continue for others this * could cause problems if the pipelining buffer is enabled. * * @author Stuart Douglas */ public class HttpContinue { private static final Set COMPATIBLE_PROTOCOLS; static { Set compat = new HashSet<>(); compat.add(Protocols.HTTP_1_1); compat.add(Protocols.HTTP_2_0); COMPATIBLE_PROTOCOLS = Collections.unmodifiableSet(compat); } public static final String CONTINUE = "100-continue"; private static final AttachmentKey ALREADY_SENT = AttachmentKey.create(Boolean.class); /** * Returns true if this exchange requires the server to send a 100 (Continue) response. * * @param exchange The exchange * @return true if the server needs to send a continue response */ public static boolean requiresContinueResponse(final HttpServerExchange exchange) { if (!COMPATIBLE_PROTOCOLS.contains(exchange.getProtocol()) || exchange.isResponseStarted() || !exchange.getConnection().isContinueResponseSupported() || exchange.getAttachment(ALREADY_SENT) != null) { return false; } HeaderMap requestHeaders = exchange.getRequestHeaders(); return requiresContinueResponse(requestHeaders); } public static boolean requiresContinueResponse(HeaderMap requestHeaders) { List expect = requestHeaders.get(Headers.EXPECT); if (expect != null) { for (String header : expect) { if (header.equalsIgnoreCase(CONTINUE)) { return true; } } } return false; } public static boolean isContinueResponseSent(HttpServerExchange exchange) { return exchange.getAttachment(ALREADY_SENT) != null; } /** * Sends a continuation using async IO, and calls back when it is complete. * * @param exchange The exchange * @param callback The completion callback */ public static void sendContinueResponse(final HttpServerExchange exchange, final IoCallback callback) { if (!exchange.isResponseChannelAvailable()) { callback.onException(exchange, null, UndertowMessages.MESSAGES.cannotSendContinueResponse()); return; } internalSendContinueResponse(exchange, callback); } /** * Creates a response sender that can be used to send a HTTP 100-continue response. * * @param exchange The exchange * @return The response sender */ public static ContinueResponseSender createResponseSender(final HttpServerExchange exchange) throws IOException { if (!exchange.isResponseChannelAvailable()) { throw UndertowMessages.MESSAGES.cannotSendContinueResponse(); } if(exchange.getAttachment(ALREADY_SENT) != null) { return new ContinueResponseSender() { @Override public boolean send() throws IOException { return true; } @Override public void awaitWritable() throws IOException { } @Override public void awaitWritable(long time, TimeUnit timeUnit) throws IOException { } }; } HttpServerExchange newExchange = exchange.getConnection().sendOutOfBandResponse(exchange); exchange.putAttachment(ALREADY_SENT, true); newExchange.setStatusCode(StatusCodes.CONTINUE); final StreamSinkChannel responseChannel = newExchange.getResponseChannel(); return new ContinueResponseSender() { boolean shutdown = false; @Override public boolean send() throws IOException { if (!shutdown) { shutdown = true; responseChannel.shutdownWrites(); } return responseChannel.flush(); } @Override public void awaitWritable() throws IOException { responseChannel.awaitWritable(); } @Override public void awaitWritable(final long time, final TimeUnit timeUnit) throws IOException { responseChannel.awaitWritable(time, timeUnit); } }; } /** * Marks a continue response as already having been sent. In general this should only be used * by low level handlers than need fine grained control over the continue response. * * @param exchange The exchange */ public static void markContinueResponseSent(HttpServerExchange exchange) { exchange.putAttachment(ALREADY_SENT, true); } /** * Sends a continue response using blocking IO * * @param exchange The exchange */ public static void sendContinueResponseBlocking(final HttpServerExchange exchange) throws IOException { if (!exchange.isResponseChannelAvailable()) { throw UndertowMessages.MESSAGES.cannotSendContinueResponse(); } if(exchange.getAttachment(ALREADY_SENT) != null) { return; } HttpServerExchange newExchange = exchange.getConnection().sendOutOfBandResponse(exchange); exchange.putAttachment(ALREADY_SENT, true); newExchange.setStatusCode(StatusCodes.CONTINUE); newExchange.getResponseHeaders().put(Headers.CONTENT_LENGTH, 0); newExchange.startBlocking(); newExchange.getOutputStream().close(); newExchange.getInputStream().close(); } /** * Sets a 417 response code and ends the exchange. * * @param exchange The exchange to reject */ public static void rejectExchange(final HttpServerExchange exchange) { exchange.setStatusCode(StatusCodes.EXPECTATION_FAILED); exchange.setPersistent(false); exchange.endExchange(); } private static void internalSendContinueResponse(final HttpServerExchange exchange, final IoCallback callback) { if(exchange.getAttachment(ALREADY_SENT) != null) { callback.onComplete(exchange, null); return; } HttpServerExchange newExchange = exchange.getConnection().sendOutOfBandResponse(exchange); exchange.putAttachment(ALREADY_SENT, true); newExchange.setStatusCode(StatusCodes.CONTINUE); final StreamSinkChannel responseChannel = newExchange.getResponseChannel(); try { responseChannel.shutdownWrites(); if (!responseChannel.flush()) { responseChannel.getWriteSetter().set(ChannelListeners.flushingChannelListener( new ChannelListener() { @Override public void handleEvent(StreamSinkChannel channel) { channel.suspendWrites(); exchange.dispatch(new HttpHandler() { @Override public void handleRequest(HttpServerExchange exchange) throws Exception { callback.onComplete(exchange, null); } }); } }, new ChannelExceptionHandler() { @Override public void handleException(Channel channel, final IOException e) { exchange.dispatch(new HttpHandler() { @Override public void handleRequest(HttpServerExchange exchange) throws Exception { callback.onException(exchange, null, e); } }); } })); responseChannel.resumeWrites(); exchange.dispatch(); } else { callback.onComplete(exchange, null); } } catch (IOException e) { callback.onException(exchange, null, e); } } /** * A continue response that is in the process of being sent. */ public interface ContinueResponseSender { /** * Continue sending the response. * * @return true if the response is fully sent, false otherwise. */ boolean send() throws IOException; void awaitWritable() throws IOException; void awaitWritable(long time, final TimeUnit timeUnit) throws IOException; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy