Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[CXF-8347] URI processing/caching/extending changes #698

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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