diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/accept/ContentTypeResolver.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/accept/ContentTypeResolver.java new file mode 100644 index 00000000000..c91c494a622 --- /dev/null +++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/accept/ContentTypeResolver.java @@ -0,0 +1,42 @@ +/* + * Copyright 2002-2016 the original author or authors. + * + * 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 org.springframework.web.reactive.accept; + +import java.util.List; + +import org.springframework.http.MediaType; +import org.springframework.web.HttpMediaTypeNotAcceptableException; +import org.springframework.web.server.ServerWebExchange; + +/** + * + * @author Rossen Stoyanchev + */ +public interface ContentTypeResolver { + + /** + * Resolve the given request to a list of requested media types. The returned + * list is ordered by specificity first and by quality parameter second. + * + * @param exchange the current exchange + * @return the requested media types or an empty list + * + * @throws HttpMediaTypeNotAcceptableException if the requested media + * types cannot be parsed + */ + List resolveMediaTypes(ServerWebExchange exchange) throws HttpMediaTypeNotAcceptableException; + +} diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/accept/FileExtensionContentTypeResolver.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/accept/FileExtensionContentTypeResolver.java new file mode 100644 index 00000000000..8343c8da7cc --- /dev/null +++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/accept/FileExtensionContentTypeResolver.java @@ -0,0 +1,45 @@ +/* + * Copyright 2002-2016 the original author or authors. + * + * 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 org.springframework.web.reactive.accept; + +import java.util.List; + +import org.springframework.http.MediaType; + +/** + * An extension of {@link ContentTypeResolver} for a resolver that uses file + * extensions and can expose file extension mappings. + * + * @author Rossen Stoyanchev + */ +public interface FileExtensionContentTypeResolver extends ContentTypeResolver { + + /** + * Resolve the given media type to a list of path extensions. + * + * @param mediaType the media type to resolve + * @return a list of extensions or an empty list, never {@code null} + */ + List getFileExtensions(MediaType mediaType); + + /** + * Return all registered file extensions. + * @return a list of extensions or an empty list, never {@code null} + */ + List getAllFileExtensions(); + +} diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/accept/HeaderContentTypeResolver.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/accept/HeaderContentTypeResolver.java new file mode 100644 index 00000000000..de6caac1507 --- /dev/null +++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/accept/HeaderContentTypeResolver.java @@ -0,0 +1,47 @@ +/* + * Copyright 2002-2016 the original author or authors. + * + * 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 org.springframework.web.reactive.accept; + +import java.util.List; + +import org.springframework.http.InvalidMediaTypeException; +import org.springframework.http.MediaType; +import org.springframework.web.HttpMediaTypeNotAcceptableException; +import org.springframework.web.server.ServerWebExchange; + +/** + * A {@link ContentTypeResolver} that checks the 'Accept' request header. + * + * @author Rossen Stoyanchev + */ +public class HeaderContentTypeResolver implements ContentTypeResolver { + + @Override + public List resolveMediaTypes(ServerWebExchange exchange) + throws HttpMediaTypeNotAcceptableException { + + try { + List mediaTypes = exchange.getRequest().getHeaders().getAccept(); + MediaType.sortBySpecificityAndQuality(mediaTypes); + return mediaTypes; + } + catch (InvalidMediaTypeException ex) { + String value = exchange.getRequest().getHeaders().getFirst("Accept"); + throw new HttpMediaTypeNotAcceptableException( + "Could not parse 'Accept' header [" + value + "]: " + ex.getMessage()); + } + } +} diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/accept/package-info.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/accept/package-info.java new file mode 100644 index 00000000000..428353ad050 --- /dev/null +++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/accept/package-info.java @@ -0,0 +1,5 @@ +/** + * This package provides support for various strategies to resolve the requested + * content type for a given request. + */ +package org.springframework.web.reactive.accept; diff --git a/spring-web-reactive/src/test/java/org/springframework/web/reactive/accept/HeaderContentTypeResolverTests.java b/spring-web-reactive/src/test/java/org/springframework/web/reactive/accept/HeaderContentTypeResolverTests.java new file mode 100644 index 00000000000..9b2288b2c41 --- /dev/null +++ b/spring-web-reactive/src/test/java/org/springframework/web/reactive/accept/HeaderContentTypeResolverTests.java @@ -0,0 +1,82 @@ +/* + * Copyright 2002-2016 the original author or authors. + * + * 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 org.springframework.web.reactive.accept; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.List; + +import org.junit.Before; +import org.junit.Test; + +import org.springframework.http.HttpMethod; +import org.springframework.http.MediaType; +import org.springframework.http.server.reactive.MockServerHttpRequest; +import org.springframework.http.server.reactive.MockServerHttpResponse; +import org.springframework.http.server.reactive.ServerHttpRequest; +import org.springframework.web.HttpMediaTypeNotAcceptableException; +import org.springframework.web.server.ServerWebExchange; +import org.springframework.web.server.adapter.DefaultServerWebExchange; +import org.springframework.web.server.session.WebSessionManager; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.mock; + +/** + * Unit tests for {@link HeaderContentTypeResolver}. + * + * @author Rossen Stoyanchev + */ +public class HeaderContentTypeResolverTests { + + private HeaderContentTypeResolver resolver; + + + @Before + public void setup() { + this.resolver = new HeaderContentTypeResolver(); + } + + + @Test + public void resolveMediaTypes() throws Exception { + ServerWebExchange exchange = createExchange("text/plain; q=0.5, text/html, text/x-dvi; q=0.8, text/x-c"); + List mediaTypes = this.resolver.resolveMediaTypes(exchange); + + assertEquals(4, mediaTypes.size()); + assertEquals("text/html", mediaTypes.get(0).toString()); + assertEquals("text/x-c", mediaTypes.get(1).toString()); + assertEquals("text/x-dvi;q=0.8", mediaTypes.get(2).toString()); + assertEquals("text/plain;q=0.5", mediaTypes.get(3).toString()); + } + + @Test(expected=HttpMediaTypeNotAcceptableException.class) + public void resolveMediaTypesParseError() throws Exception { + ServerWebExchange exchange = createExchange("textplain; q=0.5"); + this.resolver.resolveMediaTypes(exchange); + } + + + private ServerWebExchange createExchange(String accept) throws URISyntaxException { + ServerHttpRequest request = new MockServerHttpRequest(HttpMethod.GET, new URI("/")); + if (accept != null) { + request.getHeaders().add("Accept", accept); + } + WebSessionManager sessionManager = mock(WebSessionManager.class); + return new DefaultServerWebExchange(request, new MockServerHttpResponse(), sessionManager); + } + +}