Skip to content

Commit

Permalink
Improve MappingMatch determination in mock request
Browse files Browse the repository at this point in the history
MockHttpServletRequest now checks the requestURI and servletPath to
check whether they imply a Servlet path mapping, which is the case
when the requestURI is longer than the contextPath + servletPath.

This is essential when parsed patterns are in use in which case the
request path is parsed taking into account only the requestURI and
the contextPath. However, if the MappingMatch indicates a match by
Servlet path, then the servletPath is also taken into account.

See gh-28607
  • Loading branch information
rstoyanchev committed Jun 29, 2022
1 parent 9c2ad4a commit 8a9b082
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 5 deletions.
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 the original author or authors.
* Copyright 2002-2022 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.
Expand Down Expand Up @@ -52,10 +52,12 @@
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletMapping;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import jakarta.servlet.http.HttpUpgradeHandler;
import jakarta.servlet.http.MappingMatch;
import jakarta.servlet.http.Part;

import org.springframework.http.HttpHeaders;
Expand All @@ -69,6 +71,7 @@
import org.springframework.util.ObjectUtils;
import org.springframework.util.StreamUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.util.UrlPathHelper;

/**
* Mock implementation of the {@link jakarta.servlet.http.HttpServletRequest} interface.
Expand Down Expand Up @@ -274,6 +277,9 @@ public class MockHttpServletRequest implements HttpServletRequest {

private final MultiValueMap<String, Part> parts = new LinkedMultiValueMap<>();

@Nullable
private HttpServletMapping httpServletMapping;


// ---------------------------------------------------------------------
// Constructors
Expand Down Expand Up @@ -1389,6 +1395,33 @@ public Collection<Part> getParts() throws IOException, ServletException {
return result;
}

public void setHttpServletMapping(@Nullable HttpServletMapping httpServletMapping) {
this.httpServletMapping = httpServletMapping;
}

@Override
public HttpServletMapping getHttpServletMapping() {
return (this.httpServletMapping == null ?
new MockHttpServletMapping("", "", "", determineMappingMatch()) :
this.httpServletMapping);
}

/**
* Best effort to detect a Servlet path mapping, e.g. {@code "/foo/*"}, by
* checking whether the length of requestURI > contextPath + servletPath.
* This helps {@link org.springframework.web.util.ServletRequestPathUtils}
* to take into account the Servlet path when parsing the requestURI.
*/
@Nullable
private MappingMatch determineMappingMatch() {
if (StringUtils.hasText(this.requestURI) && StringUtils.hasText(this.servletPath)) {
String path = UrlPathHelper.defaultInstance.getRequestUri(this);
String prefix = this.contextPath + this.servletPath;
return (path.startsWith(prefix) && (path.length() > prefix.length()) ? MappingMatch.PATH : null);
}
return null;
}

@Override
public <T extends HttpUpgradeHandler> T upgrade(Class<T> handlerClass) throws IOException, ServletException {
throw new UnsupportedOperationException();
Expand Down
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 the original author or authors.
* Copyright 2002-2022 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.
Expand Down Expand Up @@ -57,6 +57,7 @@
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import jakarta.servlet.http.HttpUpgradeHandler;
import jakarta.servlet.http.MappingMatch;
import jakarta.servlet.http.Part;

import org.springframework.http.HttpHeaders;
Expand All @@ -70,6 +71,7 @@
import org.springframework.util.ObjectUtils;
import org.springframework.util.StreamUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.util.UrlPathHelper;

/**
* Mock implementation of the {@link jakarta.servlet.http.HttpServletRequest} interface.
Expand Down Expand Up @@ -275,7 +277,8 @@ public class MockHttpServletRequest implements HttpServletRequest {

private final MultiValueMap<String, Part> parts = new LinkedMultiValueMap<>();

private HttpServletMapping httpServletMapping = new MockHttpServletMapping("", "", "", null);
@Nullable
private HttpServletMapping httpServletMapping;


// ---------------------------------------------------------------------
Expand Down Expand Up @@ -1392,13 +1395,31 @@ public Collection<Part> getParts() throws IOException, ServletException {
return result;
}

public void setHttpServletMapping(HttpServletMapping httpServletMapping) {
public void setHttpServletMapping(@Nullable HttpServletMapping httpServletMapping) {
this.httpServletMapping = httpServletMapping;
}

@Override
public HttpServletMapping getHttpServletMapping() {
return this.httpServletMapping;
return (this.httpServletMapping == null ?
new MockHttpServletMapping("", "", "", determineMappingMatch()) :
this.httpServletMapping);
}

/**
* Best effort to detect a Servlet path mapping, e.g. {@code "/foo/*"}, by
* checking whether the length of requestURI > contextPath + servletPath.
* This helps {@link org.springframework.web.util.ServletRequestPathUtils}
* to take into account the Servlet path when parsing the requestURI.
*/
@Nullable
private MappingMatch determineMappingMatch() {
if (StringUtils.hasText(this.requestURI) && StringUtils.hasText(this.servletPath)) {
String path = UrlPathHelper.defaultInstance.getRequestUri(this);
String prefix = this.contextPath + this.servletPath;
return (path.startsWith(prefix) && (path.length() > prefix.length()) ? MappingMatch.PATH : null);
}
return null;
}

@Override
Expand Down

0 comments on commit 8a9b082

Please sign in to comment.