Skip to content

Commit

Permalink
[CXF-8347] URI processing/caching/extending changes
Browse files Browse the repository at this point in the history
Includes:
- URITemplate cache
- Extension to allow extenders to wrap runnables from HTTPConduit
- Numeric handling in URIs
- URITemplate processes parameters
- Add checking for form post when content-type includes charsets, etc.

Signed-off-by: Andy McCright <[email protected]>
  • Loading branch information
andymc12 committed Oct 1, 2020
1 parent 511907e commit b226252
Show file tree
Hide file tree
Showing 9 changed files with 932 additions and 91 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.apache.cxf.common.util;

import org.apache.cxf.message.Message;

/**
* Intended to allow extenders to wrap a Runnable by extending this class.
* The default implementation simply returns the passed-in Runnable.
*/
public class RunnableWrapperFactory {

public Runnable wrap(Runnable innerRunnable, Message m) {
return innerRunnable;
}
}
29 changes: 24 additions & 5 deletions core/src/main/java/org/apache/cxf/service/model/EndpointInfo.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,11 @@ public class EndpointInfo extends AbstractDescriptionElement implements NamedIte
ServiceInfo service;
BindingInfo binding;
QName name;
EndpointReferenceType address;
private volatile EndpointReferenceType lastAddressSet; // Keep last address set for when threadlocal val may be null

// Store address in a theadLocal to avoid issue where redirected URL is mismatched when accessed from both
// IP address and machine name.
private final ThreadLocal<EndpointReferenceType> threadLocal = new ThreadLocal<EndpointReferenceType>();

public EndpointInfo() {
}
Expand Down Expand Up @@ -89,27 +93,38 @@ public void setBinding(BindingInfo b) {
}

public String getAddress() {
EndpointReferenceType address = threadLocal.get();
if (address == null) {
address = lastAddressSet;
}
return (null != address && null != address.getAddress()) ? address.getAddress().getValue() : null;
}

public void setAddress(String addr) {
EndpointReferenceType address = threadLocal.get();
if (null == address) {
// address = EndpointReferenceUtils.getEndpointReference(addr); loads jaxb and we want to avoid it
final EndpointReferenceType reference = new EndpointReferenceType();
final AttributedURIType a = new AttributedURIType();
a.setValue(addr);
reference.setAddress(a);
address = reference;
threadLocal.set(address);
} else {
final AttributedURIType a = new AttributedURIType();
a.setValue(addr);
address.setAddress(a);
// EndpointReferenceUtils.setAddress(address, addr);
}
lastAddressSet = address;
}

public void setAddress(EndpointReferenceType endpointReference) {
address = endpointReference;
threadLocal.set(endpointReference);
lastAddressSet = endpointReference;
}

//When finished the threadlocal must be cleared.
public void resetAddress() {
threadLocal.remove();
}

@Override
Expand All @@ -134,6 +149,10 @@ public <T> T getTraversedExtensor(T defaultValue, Class<T> type) {
}

public EndpointReferenceType getTarget() {
EndpointReferenceType address = threadLocal.get();
if (address == null) {
address = lastAddressSet;
}
return address;
}

Expand All @@ -154,4 +173,4 @@ public String toString() {
+ ", ServiceQName=" + (binding.getService() == null ? "" : binding.getService().getName())))
+ ", QName=" + name;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,16 @@ public final class URITemplate {
public static final String LIMITED_REGEX_SUFFIX = "(/.*)?";
public static final String FINAL_MATCH_GROUP = "FINAL_MATCH_GROUP";
private static final String DEFAULT_PATH_VARIABLE_REGEX = "([^/]+?)";
private static final Pattern INTEGER_PATH_VARIABLE_REGEX_PATTERN = Pattern.compile("\\-?[0-9]+");
private static final Pattern DECIMAL_PATH_VARIABLE_REGEX_PATTERN =
Pattern.compile("[-+]?[0-9]*\\.?[0-9]+([eE][-+]?[0-9]+)?");
private static final String CHARACTERS_TO_ESCAPE = ".*+$()";
private static final String SLASH = "/";
private static final String SLASH_QUOTE = "/;";
private static final int MAX_URI_TEMPLATE_CACHE_SIZE =
SystemPropertyAction.getInteger("org.apache.cxf.jaxrs.max_uri_template_cache_size", 2000);
private static final Map<String, URITemplate> URI_TEMPLATE_CACHE = new ConcurrentHashMap<>();

private final String template;
private final List<String> variables = new ArrayList<>();
private final List<String> customVariables = new ArrayList<>();
Expand All @@ -58,14 +61,18 @@ public final class URITemplate {
private final List<UriChunk> uriChunks;

public URITemplate(String theTemplate) {
template = theTemplate;
this(theTemplate, Collections.<Parameter> emptyList());
}

public URITemplate(String theTemplate, List<Parameter> params) {
template = theTemplate == null ? "" : theTemplate;
StringBuilder literalChars = new StringBuilder();
StringBuilder patternBuilder = new StringBuilder();
CurlyBraceTokenizer tok = new CurlyBraceTokenizer(template);
uriChunks = new ArrayList<>();
while (tok.hasNext()) {
String templatePart = tok.next();
UriChunk chunk = UriChunk.createUriChunk(templatePart);
UriChunk chunk = UriChunk.createUriChunk(templatePart, params);
uriChunks.add(chunk);
if (chunk instanceof Literal) {
String encodedValue = HttpUtils.encodePartiallyEncoded(chunk.getValue(), false);
Expand Down Expand Up @@ -359,32 +366,65 @@ public String encodeLiteralCharacters(boolean isQuery) {
return sb.toString();
}

public static URITemplate createTemplate(Path path, List<Parameter> params, String classNameandPath) {
return createTemplate(path == null ? null : path.value(), params, classNameandPath);
}

public static URITemplate createTemplate(Path path, List<Parameter> params) {
return createTemplate(path == null ? null : path.value(), params);
}

public static URITemplate createTemplate(Path path) {
return createTemplate(path == null ? null : path.value(), Collections.<Parameter> emptyList());
}

return createTemplate(path == null ? null : path.value());
public static URITemplate createTemplate(Path path, String classNameandPath) {
return createTemplate(path == null ? null
: path.value(), Collections.<Parameter> emptyList(), classNameandPath);
}

public static URITemplate createTemplate(String pathValue) {
return createTemplate(pathValue, Collections.<Parameter> emptyList(), pathValue);
}

public static URITemplate createTemplate(String pathValue, String classNameandPath) {
return createTemplate(pathValue, Collections.<Parameter> emptyList(), classNameandPath);
}

public static URITemplate createTemplate(String pathValue, List<Parameter> params) {
return createExactTemplate(pathValue, params, pathValue);
}

public static URITemplate createTemplate(String pathValue, List<Parameter> params, String classNameandPath) {
if (pathValue == null) {
pathValue = "/";
} else if (!pathValue.startsWith("/")) {
pathValue = "/" + pathValue;
}
return createExactTemplate(pathValue);
return createExactTemplate(pathValue, params, classNameandPath);
}

public static URITemplate createExactTemplate(String pathValue) {
URITemplate template = URI_TEMPLATE_CACHE.get(pathValue);
return createExactTemplate(pathValue, Collections.<Parameter> emptyList());
}

public static URITemplate createExactTemplate(String pathValue, List<Parameter> params) {
return createExactTemplate(pathValue, params, pathValue);
}

public static URITemplate createExactTemplate(String pathValue, List<Parameter> params, String classNameandPath) {
classNameandPath = classNameandPath == null ? "" : classNameandPath;
URITemplate template = URI_TEMPLATE_CACHE.get(classNameandPath);
if (template == null) {
template = new URITemplate(pathValue);
template = new URITemplate(pathValue, params);
if (URI_TEMPLATE_CACHE.size() >= MAX_URI_TEMPLATE_CACHE_SIZE) {
URI_TEMPLATE_CACHE.clear();
}
URI_TEMPLATE_CACHE.put(pathValue, template);
URI_TEMPLATE_CACHE.put(classNameandPath, template);
}
return template;
}

public static int compareTemplates(URITemplate t1, URITemplate t2) {
int l1 = t1.getLiteralChars().length();
int l2 = t2.getLiteralChars().length();
Expand Down Expand Up @@ -422,11 +462,11 @@ private abstract static class UriChunk {
* @return If param has variable form then {@link Variable} instance is created, otherwise chunk is
* treated as {@link Literal}.
*/
public static UriChunk createUriChunk(String uriChunk) {
public static UriChunk createUriChunk(String uriChunk, List<Parameter> params) {
if (uriChunk == null || "".equals(uriChunk)) {
throw new IllegalArgumentException("uriChunk is empty");
}
UriChunk uriChunkRepresentation = Variable.create(uriChunk);
UriChunk uriChunkRepresentation = Variable.create(uriChunk, params);
if (uriChunkRepresentation == null) {
uriChunkRepresentation = Literal.create(uriChunk);
}
Expand Down Expand Up @@ -482,19 +522,37 @@ private Variable() {
* @param uriChunk uriChunk chunk that depicts variable
* @return Variable if variable was successfully created; null if uriChunk was not a variable
*/
public static Variable create(String uriChunk) {
Variable newVariable = new Variable();
public static Variable create(String uriChunk, List<Parameter> params) {
if (uriChunk == null || "".equals(uriChunk)) {
return null;
}
if (CurlyBraceTokenizer.insideBraces(uriChunk)) {
uriChunk = CurlyBraceTokenizer.stripBraces(uriChunk).trim();
Matcher matcher = VARIABLE_PATTERN.matcher(uriChunk);
if (matcher.matches()) {
Variable newVariable = new Variable();
newVariable.name = matcher.group(1).trim();
if (matcher.group(2) != null && matcher.group(3) != null) {
String patternExpression = matcher.group(3).trim();
newVariable.pattern = Pattern.compile(patternExpression);
} else {
//check parameter types
for (Parameter p : params) {
if (p.getName() != null && p.getName().equals(newVariable.name)) {
Class<?> paramType = p.getJavaType();
//CHECKSTYLE:OFF
if (paramType.isPrimitive()) {
if (int.class.equals(paramType) || short.class.equals(paramType)
|| long.class.equals(paramType)) {
newVariable.pattern = INTEGER_PATH_VARIABLE_REGEX_PATTERN;
} else if (double.class.equals(paramType) || float.class.equals(paramType)) {
newVariable.pattern = DECIMAL_PATH_VARIABLE_REGEX_PATTERN;
}
}
//CHECKSTYLE:ON
break;
}
}
}
return newVariable;
}
Expand Down Expand Up @@ -548,16 +606,18 @@ public String getValue() {
*/
static class CurlyBraceTokenizer {

private List<String> tokens = new ArrayList<>();
private final List<String> tokens = new ArrayList<>();
private int tokenIdx;

CurlyBraceTokenizer(String string) {
boolean outside = true;
int level = 0;
int lastIdx = 0;
int idx;
for (idx = 0; idx < string.length(); idx++) {
if (string.charAt(idx) == '{') {
int length = string.length();
for (idx = 0; idx < length; idx++) {
char c = string.charAt(idx);
if (c == '{') {
if (outside) {
if (lastIdx < idx) {
tokens.add(string.substring(lastIdx, idx));
Expand All @@ -567,20 +627,20 @@ static class CurlyBraceTokenizer {
} else {
level++;
}
} else if (string.charAt(idx) == '}' && !outside) {
} else if (c == '}' && !outside) {
if (level > 0) {
level--;
} else {
if (lastIdx < idx) {
tokens.add(string.substring(lastIdx, idx + 1));
tokens.add(lastIdx == 0 && idx + 1 == length ? string : string.substring(lastIdx, idx + 1));
}
lastIdx = idx + 1;
outside = true;
}
}
}
if (lastIdx < idx) {
tokens.add(string.substring(lastIdx, idx));
tokens.add(lastIdx == 0 ? string : string.substring(lastIdx, idx));
}
}

Expand Down Expand Up @@ -621,6 +681,4 @@ public String next() {
throw new IllegalStateException("no more elements");
}
}
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,8 @@ private static void checkNumberOfParts(Message m, int numberOfParts) {
}

public static boolean isFormPostRequest(Message m) {
return MediaType.APPLICATION_FORM_URLENCODED.equals(m.get(Message.CONTENT_TYPE))
String contentType = (String) m.get(Message.CONTENT_TYPE);
return (contentType != null && contentType.toLowerCase().startsWith(MediaType.APPLICATION_FORM_URLENCODED))
&& HttpMethod.POST.equals(m.get(Message.HTTP_REQUEST_METHOD));
}
}
Loading

0 comments on commit b226252

Please sign in to comment.