Skip to content

Commit

Permalink
REST: Take into account HTTP method specified when matching a URL to …
Browse files Browse the repository at this point in the history
…redirect to
  • Loading branch information
graemerocher committed May 15, 2013
1 parent 390d29a commit bc767aa
Show file tree
Hide file tree
Showing 7 changed files with 85 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
package org.codehaus.groovy.grails.web.mapping;

import grails.util.GrailsNameUtils;
import grails.web.CamelCaseUrlConverter;
import grails.web.UrlConverter;

import java.util.Collections;
Expand Down Expand Up @@ -59,13 +60,28 @@ public class DefaultUrlMappingInfo extends AbstractUrlMappingInfo {
private boolean parsingRequest;
private Object uri;
private UrlConverter urlConverter;
private String httpMethod;

@SuppressWarnings({"unchecked","rawtypes"})
private DefaultUrlMappingInfo(Map params, UrlMappingData urlData, ServletContext servletContext) {
setParams(params);
id = getParams().get(ID_PARAM);
this.urlData = urlData;
this.servletContext = servletContext;
ApplicationContext applicationContext = WebUtils.findApplicationContext(servletContext);
if(applicationContext != null) {
urlConverter = applicationContext.getBean(UrlConverter.BEAN_NAME, UrlConverter.class);
}
else {
urlConverter = new CamelCaseUrlConverter();
}
}
private DefaultUrlMappingInfo(String httpMethod,Map params, UrlMappingData urlData, ServletContext servletContext) {
setParams(params);
id = getParams().get(ID_PARAM);
this.urlData = urlData;
this.servletContext = servletContext;
this.httpMethod = httpMethod;
GrailsApplication grailsApplication = WebUtils.lookupApplication(servletContext);
ApplicationContext mainContext = grailsApplication.getMainContext();
urlConverter = mainContext.getBean(UrlConverter.BEAN_NAME, UrlConverter.class);
Expand All @@ -74,12 +90,17 @@ private DefaultUrlMappingInfo(Map params, UrlMappingData urlData, ServletContext
@SuppressWarnings("rawtypes")
public DefaultUrlMappingInfo(Object controllerName, Object actionName, Object pluginName, Object viewName, Map params,
UrlMappingData urlData, ServletContext servletContext) {
this(controllerName, actionName, pluginName, viewName, null, params, urlData, servletContext);
}
public DefaultUrlMappingInfo(Object controllerName, Object actionName, Object pluginName, Object viewName, String httpMethod, Map params,
UrlMappingData urlData, ServletContext servletContext) {
this(params, urlData, servletContext);
Assert.isTrue(controllerName != null || viewName != null, "URL mapping must either provide a controller or view name to map to!");
Assert.notNull(params, "Argument [params] cannot be null");
this.controllerName = controllerName;
this.actionName = actionName;
this.pluginName = pluginName;
this.httpMethod = httpMethod;
if (actionName == null) {
this.viewName = viewName;
}
Expand All @@ -97,6 +118,18 @@ public DefaultUrlMappingInfo(Object uri, UrlMappingData data, ServletContext ser
this.uri = uri;
Assert.notNull(uri, "Argument [uri] cannot be null or blank");
}
public DefaultUrlMappingInfo(Object uri,String httpMethod, UrlMappingData data, ServletContext servletContext) {
this(Collections.EMPTY_MAP, data, servletContext);
this.uri = uri;
this.httpMethod = httpMethod;
Assert.notNull(uri, "Argument [uri] cannot be null or blank");
}


@Override
public String getHttpMethod() {
return httpMethod;
}

@Override
public String toString() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -379,7 +379,9 @@ public UrlMappingInfo[] matchAll(String uri, String httpMethod) {
LOG.debug("Matched URI [" + uri + "] with pattern [" + mapping.getUrlData().getUrlPattern() + "], adding to posibilities");
}

matchingUrls.add(current);
String mappingHttpMethod = current.getHttpMethod();
if(mappingHttpMethod == null || mappingHttpMethod.equalsIgnoreCase(httpMethod))
matchingUrls.add(current);
}
}
cachedListMatches.put(uri, matchingUrls);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -518,13 +518,13 @@ private UrlMappingInfo createUrlMappingInfo(String uri, Matcher m) {

DefaultUrlMappingInfo info;
if (forwardURI != null && controllerName == null) {
info = new DefaultUrlMappingInfo(forwardURI, urlData, servletContext);
info = new DefaultUrlMappingInfo(forwardURI,getHttpMethod(), urlData, servletContext);
}
else if (viewName != null && controllerName == null) {
info = new DefaultUrlMappingInfo(viewName, params, urlData, servletContext);
}
else {
info = new DefaultUrlMappingInfo(controllerName, actionName, pluginName, getViewName(), params, urlData, servletContext);
info = new DefaultUrlMappingInfo(controllerName, actionName, pluginName, getViewName(), getHttpMethod(), params, urlData, servletContext);
}

if (parseRequest) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ import spock.lang.Specification
class UrlMappingsWithHttpMethodSpec extends Specification{

def mappings = {
"/foo"( controller:"bar", method:"POST" )
"/foo"( controller:"bar", action:"save", method:"POST" )
"/foo"( controller:"bar", action:"update", method:"PUT" )

}

Expand All @@ -22,8 +23,30 @@ class UrlMappingsWithHttpMethodSpec extends Specification{
def mappings = evaluator.evaluateMappings mappings

then:"The mapping only accepts POST requests"
mappings.size() == 1
mappings.size() == 2
mappings[0].httpMethod == 'POST'
mappings[1].httpMethod == 'PUT'

}

void "Test that URL mappings can be applied only to a certain HTTP method"() {
when:"A URL is matched for a valid HTTP method"
def results = urlMappingsHolder.matchAll('/foo', 'POST')
then:"A match is found"
results.size() == 1
results[0].controllerName == 'bar'
results[0].actionName == 'save'

when:"A URL is matched with an invalid HTTP method"
results = urlMappingsHolder.matchAll('/foo', 'GET')
then:"No results are found"
results.size() == 0

}

UrlMappingsHolder getUrlMappingsHolder() {
def evaluator = new DefaultUrlMappingEvaluator(new MockServletContext())
def mappings = evaluator.evaluateMappings mappings
return new DefaultUrlMappingsHolder(mappings)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ class ForwardUrlMappingInfo extends AbstractUrlMappingInfo {
String viewName
String URI
String id
String httpMethod
Map parameters = new HashMap()

void setController(String controller) { controllerName = controller }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,13 @@ public interface UrlMappingInfo {
*/
String getURI();

/**
* The HTTP method that this URL mapping maps to
*
* @return The http method
*/
String getHttpMethod();

/**
* The name of the controller that the URL mapping maps to
*
Expand All @@ -51,6 +58,11 @@ public interface UrlMappingInfo {
*/
String getActionName();

/**
* The name of the plugin that this UrlMappingInfo maps to
*
* @return The plugin name
*/
String getPluginName();

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,15 @@ public static GrailsApplication lookupApplication(ServletContext servletContext)
return (GrailsApplication)wac.getBean(GrailsApplication.APPLICATION_ID);
}

/**
* Locates the ApplicationContext, returns null if not found
* @param servletContext The servlet context
* @return The ApplicationContext
*/
public static ApplicationContext findApplicationContext(ServletContext servletContext) {
return WebApplicationContextUtils.getWebApplicationContext(servletContext);
}

/**
* Resolves a view for the given view and UrlMappingInfo instance
*
Expand Down

0 comments on commit bc767aa

Please sign in to comment.