Browse Source

Defensive concurrent access to shared file extension data structures

Closes gh-23064
pull/23837/head
Juergen Hoeller 6 years ago
parent
commit
1956cb1e57
  1. 24
      spring-web/src/main/java/org/springframework/web/accept/MappingMediaTypeFileExtensionResolver.java

24
spring-web/src/main/java/org/springframework/web/accept/MappingMediaTypeFileExtensionResolver.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2019 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.
@ -23,11 +23,10 @@ import java.util.Locale; @@ -23,11 +23,10 @@ import java.util.Locale;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CopyOnWriteArrayList;
import org.springframework.http.MediaType;
import org.springframework.lang.Nullable;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
/**
* An implementation of {@code MediaTypeFileExtensionResolver} that maintains
@ -37,15 +36,16 @@ import org.springframework.util.MultiValueMap; @@ -37,15 +36,16 @@ import org.springframework.util.MultiValueMap;
* Subsequently subclasses can use {@link #addMapping} to add more mappings.
*
* @author Rossen Stoyanchev
* @author Juergen Hoeller
* @since 3.2
*/
public class MappingMediaTypeFileExtensionResolver implements MediaTypeFileExtensionResolver {
private final ConcurrentMap<String, MediaType> mediaTypes = new ConcurrentHashMap<>(64);
private final MultiValueMap<MediaType, String> fileExtensions = new LinkedMultiValueMap<>();
private final ConcurrentMap<MediaType, List<String>> fileExtensions = new ConcurrentHashMap<>(64);
private final List<String> allFileExtensions = new ArrayList<>();
private final List<String> allFileExtensions = new CopyOnWriteArrayList<>();
/**
@ -53,12 +53,14 @@ public class MappingMediaTypeFileExtensionResolver implements MediaTypeFileExten @@ -53,12 +53,14 @@ public class MappingMediaTypeFileExtensionResolver implements MediaTypeFileExten
*/
public MappingMediaTypeFileExtensionResolver(@Nullable Map<String, MediaType> mediaTypes) {
if (mediaTypes != null) {
List<String> allFileExtensions = new ArrayList<>();
mediaTypes.forEach((extension, mediaType) -> {
String lowerCaseExtension = extension.toLowerCase(Locale.ENGLISH);
this.mediaTypes.put(lowerCaseExtension, mediaType);
this.fileExtensions.add(mediaType, lowerCaseExtension);
this.allFileExtensions.add(lowerCaseExtension);
addFileExtension(mediaType, extension);
allFileExtensions.add(lowerCaseExtension);
});
this.allFileExtensions.addAll(allFileExtensions);
}
}
@ -77,11 +79,17 @@ public class MappingMediaTypeFileExtensionResolver implements MediaTypeFileExten @@ -77,11 +79,17 @@ public class MappingMediaTypeFileExtensionResolver implements MediaTypeFileExten
protected void addMapping(String extension, MediaType mediaType) {
MediaType previous = this.mediaTypes.putIfAbsent(extension, mediaType);
if (previous == null) {
this.fileExtensions.add(mediaType, extension);
addFileExtension(mediaType, extension);
this.allFileExtensions.add(extension);
}
}
private void addFileExtension(MediaType mediaType, String extension) {
List<String> newList = new CopyOnWriteArrayList<>();
List<String> oldList = this.fileExtensions.putIfAbsent(mediaType, newList);
(oldList != null ? oldList : newList).add(extension);
}
@Override
public List<String> resolveFileExtensions(MediaType mediaType) {

Loading…
Cancel
Save