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