001/* 002 * Copyright 2002-2018 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.http.server.reactive; 018 019import java.io.IOException; 020import java.net.URISyntaxException; 021import java.nio.ByteBuffer; 022import java.nio.charset.Charset; 023 024import javax.servlet.AsyncContext; 025import javax.servlet.ServletResponse; 026import javax.servlet.http.HttpServletRequest; 027import javax.servlet.http.HttpServletResponse; 028 029import org.eclipse.jetty.http.HttpFields; 030import org.eclipse.jetty.server.HttpOutput; 031import org.eclipse.jetty.server.Request; 032import org.eclipse.jetty.server.Response; 033 034import org.springframework.core.io.buffer.DataBuffer; 035import org.springframework.core.io.buffer.DataBufferFactory; 036import org.springframework.http.HttpHeaders; 037import org.springframework.http.MediaType; 038import org.springframework.util.Assert; 039 040/** 041 * {@link ServletHttpHandlerAdapter} extension that uses Jetty APIs for writing 042 * to the response with {@link ByteBuffer}. 043 * 044 * @author Violeta Georgieva 045 * @author Brian Clozel 046 * @since 5.0 047 * @see org.springframework.web.server.adapter.AbstractReactiveWebInitializer 048 */ 049public class JettyHttpHandlerAdapter extends ServletHttpHandlerAdapter { 050 051 public JettyHttpHandlerAdapter(HttpHandler httpHandler) { 052 super(httpHandler); 053 } 054 055 056 @Override 057 protected ServletServerHttpRequest createRequest(HttpServletRequest request, AsyncContext context) 058 throws IOException, URISyntaxException { 059 060 Assert.notNull(getServletPath(), "Servlet path is not initialized"); 061 return new JettyServerHttpRequest(request, context, getServletPath(), getDataBufferFactory(), getBufferSize()); 062 } 063 064 @Override 065 protected ServletServerHttpResponse createResponse(HttpServletResponse response, 066 AsyncContext context, ServletServerHttpRequest request) throws IOException { 067 068 return new JettyServerHttpResponse( 069 response, context, getDataBufferFactory(), getBufferSize(), request); 070 } 071 072 073 private static final class JettyServerHttpRequest extends ServletServerHttpRequest { 074 075 JettyServerHttpRequest(HttpServletRequest request, AsyncContext asyncContext, 076 String servletPath, DataBufferFactory bufferFactory, int bufferSize) 077 throws IOException, URISyntaxException { 078 079 super(createHeaders(request), request, asyncContext, servletPath, bufferFactory, bufferSize); 080 } 081 082 private static HttpHeaders createHeaders(HttpServletRequest request) { 083 HttpFields fields = ((Request) request).getMetaData().getFields(); 084 return new HttpHeaders(new JettyHeadersAdapter(fields)); 085 } 086 } 087 088 089 private static final class JettyServerHttpResponse extends ServletServerHttpResponse { 090 091 JettyServerHttpResponse(HttpServletResponse response, AsyncContext asyncContext, 092 DataBufferFactory bufferFactory, int bufferSize, ServletServerHttpRequest request) 093 throws IOException { 094 095 super(createHeaders(response), response, asyncContext, bufferFactory, bufferSize, request); 096 } 097 098 private static HttpHeaders createHeaders(HttpServletResponse response) { 099 HttpFields fields = ((Response) response).getHttpFields(); 100 return new HttpHeaders(new JettyHeadersAdapter(fields)); 101 } 102 103 @Override 104 protected void applyHeaders() { 105 HttpServletResponse response = getNativeResponse(); 106 MediaType contentType = null; 107 try { 108 contentType = getHeaders().getContentType(); 109 } 110 catch (Exception ex) { 111 String rawContentType = getHeaders().getFirst(HttpHeaders.CONTENT_TYPE); 112 response.setContentType(rawContentType); 113 } 114 if (response.getContentType() == null && contentType != null) { 115 response.setContentType(contentType.toString()); 116 } 117 Charset charset = (contentType != null ? contentType.getCharset() : null); 118 if (response.getCharacterEncoding() == null && charset != null) { 119 response.setCharacterEncoding(charset.name()); 120 } 121 long contentLength = getHeaders().getContentLength(); 122 if (contentLength != -1) { 123 response.setContentLengthLong(contentLength); 124 } 125 } 126 127 @Override 128 protected int writeToOutputStream(DataBuffer dataBuffer) throws IOException { 129 ByteBuffer input = dataBuffer.asByteBuffer(); 130 int len = input.remaining(); 131 ServletResponse response = getNativeResponse(); 132 ((HttpOutput) response.getOutputStream()).write(input); 133 return len; 134 } 135 } 136 137}