001/* 002 * Copyright 2002-2020 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.web.multipart.support; 018 019import java.io.ByteArrayInputStream; 020import java.io.IOException; 021import java.io.InputStream; 022import java.nio.charset.Charset; 023 024import javax.servlet.http.HttpServletRequest; 025import javax.servlet.http.Part; 026 027import org.springframework.http.HttpHeaders; 028import org.springframework.http.MediaType; 029import org.springframework.http.server.ServerHttpRequest; 030import org.springframework.http.server.ServletServerHttpRequest; 031import org.springframework.lang.Nullable; 032import org.springframework.web.multipart.MultipartException; 033import org.springframework.web.multipart.MultipartFile; 034import org.springframework.web.multipart.MultipartHttpServletRequest; 035import org.springframework.web.multipart.MultipartResolver; 036 037/** 038 * {@link ServerHttpRequest} implementation that accesses one part of a multipart 039 * request. If using {@link MultipartResolver} configuration the part is accessed 040 * through a {@link MultipartFile}. Or if using Servlet 3.0 multipart processing 041 * the part is accessed through {@code ServletRequest.getPart}. 042 * 043 * @author Rossen Stoyanchev 044 * @author Juergen Hoeller 045 * @since 3.1 046 */ 047public class RequestPartServletServerHttpRequest extends ServletServerHttpRequest { 048 049 private final MultipartHttpServletRequest multipartRequest; 050 051 private final String requestPartName; 052 053 private final HttpHeaders multipartHeaders; 054 055 056 /** 057 * Create a new {@code RequestPartServletServerHttpRequest} instance. 058 * @param request the current servlet request 059 * @param requestPartName the name of the part to adapt to the {@link ServerHttpRequest} contract 060 * @throws MissingServletRequestPartException if the request part cannot be found 061 * @throws MultipartException if MultipartHttpServletRequest cannot be initialized 062 */ 063 public RequestPartServletServerHttpRequest(HttpServletRequest request, String requestPartName) 064 throws MissingServletRequestPartException { 065 066 super(request); 067 068 this.multipartRequest = MultipartResolutionDelegate.asMultipartHttpServletRequest(request); 069 this.requestPartName = requestPartName; 070 071 HttpHeaders multipartHeaders = this.multipartRequest.getMultipartHeaders(requestPartName); 072 if (multipartHeaders == null) { 073 throw new MissingServletRequestPartException(requestPartName); 074 } 075 this.multipartHeaders = multipartHeaders; 076 } 077 078 079 @Override 080 public HttpHeaders getHeaders() { 081 return this.multipartHeaders; 082 } 083 084 @Override 085 public InputStream getBody() throws IOException { 086 // Prefer Servlet Part resolution to cover file as well as parameter streams 087 boolean servletParts = (this.multipartRequest instanceof StandardMultipartHttpServletRequest); 088 if (servletParts) { 089 Part part = retrieveServletPart(); 090 if (part != null) { 091 return part.getInputStream(); 092 } 093 } 094 095 // Spring-style distinction between MultipartFile and String parameters 096 MultipartFile file = this.multipartRequest.getFile(this.requestPartName); 097 if (file != null) { 098 return file.getInputStream(); 099 } 100 String paramValue = this.multipartRequest.getParameter(this.requestPartName); 101 if (paramValue != null) { 102 return new ByteArrayInputStream(paramValue.getBytes(determineCharset())); 103 } 104 105 // Fallback: Servlet Part resolution even if not indicated 106 if (!servletParts) { 107 Part part = retrieveServletPart(); 108 if (part != null) { 109 return part.getInputStream(); 110 } 111 } 112 113 throw new IllegalStateException("No body available for request part '" + this.requestPartName + "'"); 114 } 115 116 @Nullable 117 private Part retrieveServletPart() { 118 try { 119 return this.multipartRequest.getPart(this.requestPartName); 120 } 121 catch (Exception ex) { 122 throw new MultipartException("Failed to retrieve request part '" + this.requestPartName + "'", ex); 123 } 124 } 125 126 private Charset determineCharset() { 127 MediaType contentType = getHeaders().getContentType(); 128 if (contentType != null) { 129 Charset charset = contentType.getCharset(); 130 if (charset != null) { 131 return charset; 132 } 133 } 134 String encoding = this.multipartRequest.getCharacterEncoding(); 135 return (encoding != null ? Charset.forName(encoding) : FORM_CHARSET); 136 } 137 138}