[OLINGO-472] Absolute Uris are not longer allowed

Signed-off-by: Christian Amend <chrisam@apache.org>
This commit is contained in:
Christian Holzer 2014-12-01 17:18:05 +01:00 committed by Christian Amend
parent 520acbce85
commit 297950a8d0
20 changed files with 287 additions and 205 deletions

View File

@ -42,6 +42,7 @@ import org.apache.olingo.client.api.communication.response.ODataBatchResponse;
import org.apache.olingo.client.api.communication.response.ODataEntityCreateResponse; import org.apache.olingo.client.api.communication.response.ODataEntityCreateResponse;
import org.apache.olingo.client.api.communication.response.ODataEntityUpdateResponse; import org.apache.olingo.client.api.communication.response.ODataEntityUpdateResponse;
import org.apache.olingo.client.api.communication.response.ODataResponse; import org.apache.olingo.client.api.communication.response.ODataResponse;
import org.apache.olingo.client.api.uri.UriFormat;
import org.apache.olingo.client.api.uri.v4.URIBuilder; import org.apache.olingo.client.api.uri.v4.URIBuilder;
import org.apache.olingo.client.core.communication.request.batch.ODataChangesetResponseItem; import org.apache.olingo.client.core.communication.request.batch.ODataChangesetResponseItem;
import org.apache.olingo.client.core.uri.URIUtils; import org.apache.olingo.client.core.uri.URIUtils;
@ -65,6 +66,7 @@ public class BatchClientITCase extends AbstractTestITCase {
@Before @Before
public void setup() { public void setup() {
client.getConfiguration().setContinueOnError(false); client.getConfiguration().setContinueOnError(false);
client.getConfiguration().setBatchUriFormat(UriFormat.RELATIVE);
} }
@Test @Test
@ -162,7 +164,6 @@ public class BatchClientITCase extends AbstractTestITCase {
@Test @Test
public void testErrorWithContinueOnErrorPreferHeader() { public void testErrorWithContinueOnErrorPreferHeader() {
client.getConfiguration().setContinueOnError(true); client.getConfiguration().setContinueOnError(true);
final ODataBatchRequest request = client.getBatchRequestFactory().getBatchRequest(SERVICE_URI); final ODataBatchRequest request = client.getBatchRequestFactory().getBatchRequest(SERVICE_URI);
request.setAccept(ACCEPT); request.setAccept(ACCEPT);
@ -446,7 +447,7 @@ public class BatchClientITCase extends AbstractTestITCase {
} }
private void appendGetRequest(final BatchManager manager, final String segment, final Object key) { private void appendGetRequest(final BatchManager manager, final String segment, final Object key) {
URIBuilder targetURI = client.newURIBuilder(SERVICE_URI); URIBuilder targetURI = client.newBatchURIBuilder(SERVICE_URI);
targetURI.appendEntitySetSegment(segment).appendKeySegment(key); targetURI.appendEntitySetSegment(segment).appendKeySegment(key);
ODataEntityRequest<ODataEntity> queryReq = client.getRetrieveRequestFactory().getEntityRequest(targetURI.build()); ODataEntityRequest<ODataEntity> queryReq = client.getRetrieveRequestFactory().getEntityRequest(targetURI.build());

View File

@ -53,6 +53,8 @@ public interface CommonODataClient<UT extends CommonUpdateType> {
CommonURIBuilder<?> newURIBuilder(String serviceRoot); CommonURIBuilder<?> newURIBuilder(String serviceRoot);
CommonURIBuilder<?> newBatchURIBuilder(String serviceRoot);
CommonFilterFactory getFilterFactory(); CommonFilterFactory getFilterFactory();
ODataSerializer getSerializer(ODataFormat format); ODataSerializer getSerializer(ODataFormat format);

View File

@ -22,6 +22,7 @@ import java.util.concurrent.ExecutorService;
import org.apache.olingo.client.api.http.HttpClientFactory; import org.apache.olingo.client.api.http.HttpClientFactory;
import org.apache.olingo.client.api.http.HttpUriRequestFactory; import org.apache.olingo.client.api.http.HttpUriRequestFactory;
import org.apache.olingo.client.api.uri.UriFormat;
import org.apache.olingo.commons.api.format.ContentType; import org.apache.olingo.commons.api.format.ContentType;
import org.apache.olingo.commons.api.format.ODataFormat; import org.apache.olingo.commons.api.format.ODataFormat;
@ -270,4 +271,17 @@ public interface Configuration {
*/ */
void setExecutor(ExecutorService executorService); void setExecutor(ExecutorService executorService);
/**
* Returns the current URI format
*
* @return current URI format
*/
UriFormat getUriFormat();
/**
* Sets the current URI format
*
* @param format new URI format
*/
void setBatchUriFormat(UriFormat format);
} }

View File

@ -0,0 +1,38 @@
/*
* 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.olingo.client.api.uri;
/**
* Determines if absolute or relative URIs are used
*/
public enum UriFormat {
/**
* Relative URI
*
* Example People(1)
*/
RELATIVE,
/**
* Absolute URI
*
* Example https://host:1234/path/service/People(1)
*/
ABSOLUTE;
}

View File

@ -45,6 +45,9 @@ public interface ODataClient extends CommonODataClient<UpdateType> {
@Override @Override
URIBuilder newURIBuilder(String serviceRoot); URIBuilder newURIBuilder(String serviceRoot);
@Override
URIBuilder newBatchURIBuilder(String serviceRoot);
@Override @Override
FilterFactory getFilterFactory(); FilterFactory getFilterFactory();

View File

@ -47,6 +47,9 @@ public interface ODataClient extends CommonODataClient<UpdateType> {
@Override @Override
URIBuilder newURIBuilder(String serviceRoot); URIBuilder newURIBuilder(String serviceRoot);
@Override
URIBuilder newBatchURIBuilder(String serviceRoot);
@Override @Override
FilterFactory getFilterFactory(); FilterFactory getFilterFactory();

View File

@ -26,6 +26,7 @@ import java.util.concurrent.Executors;
import org.apache.olingo.client.api.Configuration; import org.apache.olingo.client.api.Configuration;
import org.apache.olingo.client.api.http.HttpClientFactory; import org.apache.olingo.client.api.http.HttpClientFactory;
import org.apache.olingo.client.api.http.HttpUriRequestFactory; import org.apache.olingo.client.api.http.HttpUriRequestFactory;
import org.apache.olingo.client.api.uri.UriFormat;
import org.apache.olingo.client.core.http.DefaultHttpClientFactory; import org.apache.olingo.client.core.http.DefaultHttpClientFactory;
import org.apache.olingo.client.core.http.DefaultHttpUriRequestFactory; import org.apache.olingo.client.core.http.DefaultHttpUriRequestFactory;
import org.apache.olingo.commons.api.format.ContentType; import org.apache.olingo.commons.api.format.ContentType;
@ -59,6 +60,8 @@ public class ConfigurationImpl implements Configuration {
private static final String CONTINUE_ON_ERROR = "continueOnError"; private static final String CONTINUE_ON_ERROR = "continueOnError";
private static final String BATCH_URI_FORMAT = "batchUriFormat";
private final Map<String, Object> CONF = new HashMap<String, Object>(); private final Map<String, Object> CONF = new HashMap<String, Object>();
private transient ExecutorService executor = Executors.newFixedThreadPool(10); private transient ExecutorService executor = Executors.newFixedThreadPool(10);
@ -230,4 +233,14 @@ public class ConfigurationImpl implements Configuration {
public void setExecutor(final ExecutorService executorService) { public void setExecutor(final ExecutorService executorService) {
executor = executorService; executor = executorService;
} }
@Override
public UriFormat getUriFormat() {
return (UriFormat) getProperty(BATCH_URI_FORMAT, UriFormat.ABSOLUTE);
}
@Override
public void setBatchUriFormat(UriFormat format) {
setProperty(BATCH_URI_FORMAT, format);
}
} }

View File

@ -62,6 +62,7 @@ public abstract class AbstractURIBuilder<UB extends CommonURIBuilder<?>> impleme
return value; return value;
} }
} }
/** /**
* Logger. * Logger.
*/ */
@ -94,6 +95,7 @@ public abstract class AbstractURIBuilder<UB extends CommonURIBuilder<?>> impleme
this.version = version; this.version = version;
this.configuration = configuration; this.configuration = configuration;
segments.add(new Segment(SegmentType.SERVICEROOT, serviceRoot)); segments.add(new Segment(SegmentType.SERVICEROOT, serviceRoot));
} }
@ -268,6 +270,7 @@ public abstract class AbstractURIBuilder<UB extends CommonURIBuilder<?>> impleme
@Override @Override
public URI build() { public URI build() {
final StringBuilder segmentsBuilder = new StringBuilder(); final StringBuilder segmentsBuilder = new StringBuilder();
for (Segment seg : segments) { for (Segment seg : segments) {
if (segmentsBuilder.length() > 0 && seg.getType() != SegmentType.KEY) { if (segmentsBuilder.length() > 0 && seg.getType() != SegmentType.KEY) {
switch (seg.getType()) { switch (seg.getType()) {

View File

@ -0,0 +1,35 @@
/*
* 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.olingo.client.core.uri.v3;
import org.apache.olingo.client.api.Configuration;
import org.apache.olingo.client.api.uri.UriFormat;
import org.apache.olingo.client.api.uri.v3.URIBuilder;
import org.apache.olingo.commons.api.edm.constants.ODataServiceVersion;
public class BatchURIBuilderImpl extends URIBuilderImpl implements URIBuilder {
public BatchURIBuilderImpl(ODataServiceVersion version, Configuration configuration, String serviceRoot) {
super(version, configuration, serviceRoot);
if (configuration.getUriFormat() == UriFormat.RELATIVE && segments.size() >= 0) {
segments.remove(0);
}
}
}

View File

@ -0,0 +1,36 @@
/*
* 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.olingo.client.core.uri.v4;
import org.apache.olingo.client.api.Configuration;
import org.apache.olingo.client.api.uri.UriFormat;
import org.apache.olingo.client.api.uri.v4.URIBuilder;
import org.apache.olingo.commons.api.edm.constants.ODataServiceVersion;
public class BatchURIBuilderImpl extends URIBuilderImpl implements URIBuilder {
public BatchURIBuilderImpl(ODataServiceVersion version, Configuration configuration, String serviceRoot) {
super(version, configuration, serviceRoot);
if(configuration.getUriFormat() == UriFormat.RELATIVE && segments.size() >= 0) {
segments.remove(0);
}
}
}

View File

@ -40,6 +40,7 @@ import org.apache.olingo.client.core.communication.request.retrieve.v3.RetrieveR
import org.apache.olingo.client.core.serialization.v3.ODataBinderImpl; import org.apache.olingo.client.core.serialization.v3.ODataBinderImpl;
import org.apache.olingo.client.core.serialization.v3.ODataDeserializerImpl; import org.apache.olingo.client.core.serialization.v3.ODataDeserializerImpl;
import org.apache.olingo.client.core.serialization.v3.ODataReaderImpl; import org.apache.olingo.client.core.serialization.v3.ODataReaderImpl;
import org.apache.olingo.client.core.uri.v3.BatchURIBuilderImpl;
import org.apache.olingo.client.core.uri.v3.FilterFactoryImpl; import org.apache.olingo.client.core.uri.v3.FilterFactoryImpl;
import org.apache.olingo.client.core.uri.v3.URIBuilderImpl; import org.apache.olingo.client.core.uri.v3.URIBuilderImpl;
import org.apache.olingo.commons.api.domain.v3.ODataObjectFactory; import org.apache.olingo.commons.api.domain.v3.ODataObjectFactory;
@ -87,6 +88,11 @@ public class ODataClientImpl extends AbstractODataClient<UpdateType> implements
return new URIBuilderImpl(getServiceVersion(), configuration, serviceRoot); return new URIBuilderImpl(getServiceVersion(), configuration, serviceRoot);
} }
@Override
public URIBuilder newBatchURIBuilder(String serviceRoot) {
return new BatchURIBuilderImpl(getServiceVersion(), getConfiguration(), serviceRoot);
}
@Override @Override
public FilterFactory getFilterFactory() { public FilterFactory getFilterFactory() {
return filterFactory; return filterFactory;

View File

@ -43,6 +43,7 @@ import org.apache.olingo.client.core.communication.request.v4.AsyncRequestFactor
import org.apache.olingo.client.core.serialization.v4.ODataBinderImpl; import org.apache.olingo.client.core.serialization.v4.ODataBinderImpl;
import org.apache.olingo.client.core.serialization.v4.ODataDeserializerImpl; import org.apache.olingo.client.core.serialization.v4.ODataDeserializerImpl;
import org.apache.olingo.client.core.serialization.v4.ODataReaderImpl; import org.apache.olingo.client.core.serialization.v4.ODataReaderImpl;
import org.apache.olingo.client.core.uri.v4.BatchURIBuilderImpl;
import org.apache.olingo.client.core.uri.v4.FilterFactoryImpl; import org.apache.olingo.client.core.uri.v4.FilterFactoryImpl;
import org.apache.olingo.client.core.uri.v4.URIBuilderImpl; import org.apache.olingo.client.core.uri.v4.URIBuilderImpl;
import org.apache.olingo.commons.api.domain.v4.ODataObjectFactory; import org.apache.olingo.commons.api.domain.v4.ODataObjectFactory;
@ -93,6 +94,11 @@ public class ODataClientImpl extends AbstractODataClient<UpdateType> implements
return new URIBuilderImpl(getServiceVersion(), getConfiguration(), serviceRoot); return new URIBuilderImpl(getServiceVersion(), getConfiguration(), serviceRoot);
} }
@Override
public URIBuilder newBatchURIBuilder(String serviceRoot) {
return new BatchURIBuilderImpl(getServiceVersion(), getConfiguration(), serviceRoot);
}
@Override @Override
public FilterFactory getFilterFactory() { public FilterFactory getFilterFactory() {
return filterFactory; return filterFactory;

View File

@ -39,7 +39,8 @@ public class BatchDeserializerException extends BatchException {
MISSING_CONTENT_TRANSFER_ENCODING, MISSING_CONTENT_TRANSFER_ENCODING,
MISSING_CONTENT_TYPE, MISSING_CONTENT_TYPE,
MISSING_MANDATORY_HEADER, MISSING_MANDATORY_HEADER,
FORBIDDEN_HEADER; FORBIDDEN_HEADER,
FORBIDDEN_ABSOLUTE_URI;
@Override @Override
public String getKey() { public String getKey() {

View File

@ -29,8 +29,8 @@ import org.apache.olingo.commons.api.http.HttpMethod;
import org.apache.olingo.server.api.ODataRequest; import org.apache.olingo.server.api.ODataRequest;
import org.apache.olingo.server.api.ODataResponse; import org.apache.olingo.server.api.ODataResponse;
import org.apache.olingo.server.api.batch.exception.BatchDeserializerException; import org.apache.olingo.server.api.batch.exception.BatchDeserializerException;
import org.apache.olingo.server.api.batch.exception.BatchDeserializerException.MessageKeys;
import org.apache.olingo.server.core.deserializer.batch.BatchParserCommon; import org.apache.olingo.server.core.deserializer.batch.BatchParserCommon;
import org.apache.olingo.server.core.deserializer.batch.HttpRequestStatusLine.ODataURI;
public class BatchReferenceRewriter { public class BatchReferenceRewriter {
private static final String REG_EX_REFERENCE = "\\$(.*)(/.*)?"; private static final String REG_EX_REFERENCE = "\\$(.*)(/.*)?";
@ -78,8 +78,7 @@ public class BatchReferenceRewriter {
if (request.getMethod() == HttpMethod.POST) { if (request.getMethod() == HttpMethod.POST) {
// Create entity // Create entity
// The URI of the new resource will be generated by the server and published in the location header // The URI of the new resource will be generated by the server and published in the location header
ODataURI uri = new ODataURI(response.getHeaders().get(HttpHeader.LOCATION), request.getRawBaseUri()); resourceUri = parseODataPath(response.getHeaders().get(HttpHeader.LOCATION), request.getRawBaseUri());
resourceUri = uri.getRawODataPath();
} else { } else {
// Update, Upsert (PUT, PATCH, Delete) // Update, Upsert (PUT, PATCH, Delete)
// These methods still addresses a given resource, so we use the URI given by the request // These methods still addresses a given resource, so we use the URI given by the request
@ -89,6 +88,16 @@ public class BatchReferenceRewriter {
return resourceUri; return resourceUri;
} }
private String parseODataPath(String uri, String rawBaseUri) throws BatchDeserializerException {
int index = uri.indexOf(rawBaseUri);
if(index == 0) {
return uri.substring(rawBaseUri.length());
} else {
throw new BatchDeserializerException("Invalid base uri or uri", MessageKeys.INVALID_URI, 0);
}
}
private String removeSlash(String rawODataPath, boolean first) { private String removeSlash(String rawODataPath, boolean first) {
final int indexOfSlash = rawODataPath.indexOf("/"); final int indexOfSlash = rawODataPath.indexOf("/");
if (first) { if (first) {

View File

@ -30,7 +30,6 @@ import org.apache.olingo.server.api.ODataRequest;
import org.apache.olingo.server.api.batch.exception.BatchDeserializerException; import org.apache.olingo.server.api.batch.exception.BatchDeserializerException;
import org.apache.olingo.server.api.batch.exception.BatchDeserializerException.MessageKeys; import org.apache.olingo.server.api.batch.exception.BatchDeserializerException.MessageKeys;
import org.apache.olingo.server.api.deserializer.batch.BatchRequestPart; import org.apache.olingo.server.api.deserializer.batch.BatchRequestPart;
import org.apache.olingo.server.core.deserializer.batch.HttpRequestStatusLine.ODataURI;
public class BatchRequestTransformator { public class BatchRequestTransformator {
private final String baseUri; private final String baseUri;
@ -101,10 +100,8 @@ public class BatchRequestTransformator {
final boolean isChangeSet) final boolean isChangeSet)
throws BatchDeserializerException { throws BatchDeserializerException {
final HttpRequestStatusLine statusLine = final HttpRequestStatusLine statusLine =
new HttpRequestStatusLine(operation.getHttpStatusLine(), baseUri, rawServiceResolutionUri, operation new HttpRequestStatusLine(operation.getHttpStatusLine(), baseUri, rawServiceResolutionUri);
.getHeaders());
statusLine.validateHttpMethod(isChangeSet); statusLine.validateHttpMethod(isChangeSet);
final ODataURI uri = statusLine.getUri();
validateBody(statusLine, operation); validateBody(statusLine, operation);
InputStream bodyStrean = getBodyStream(operation, statusLine); InputStream bodyStrean = getBodyStream(operation, statusLine);
@ -114,11 +111,11 @@ public class BatchRequestTransformator {
final ODataRequest request = new ODataRequest(); final ODataRequest request = new ODataRequest();
request.setBody(bodyStrean); request.setBody(bodyStrean);
request.setMethod(statusLine.getMethod()); request.setMethod(statusLine.getMethod());
request.setRawBaseUri(uri.getRawBaseUri()); request.setRawBaseUri(statusLine.getRawBaseUri());
request.setRawODataPath(uri.getRawODataPath()); request.setRawODataPath(statusLine.getRawODataPath());
request.setRawQueryPath(uri.getRawQueryPath()); request.setRawQueryPath(statusLine.getRawQueryPath());
request.setRawRequestUri(uri.getRawRequestUri()); request.setRawRequestUri(statusLine.getRawRequestUri());
request.setRawServiceResolutionUri(uri.getRawServiceResolutionUri()); request.setRawServiceResolutionUri(statusLine.getRawServiceResolutionUri());
for (final HeaderField field : operation.getHeaders()) { for (final HeaderField field : operation.getHeaders()) {
request.addHeader(field.getFieldName(), field.getValues()); request.addHeader(field.getFieldName(), field.getValues());

View File

@ -18,23 +18,20 @@
*/ */
package org.apache.olingo.server.core.deserializer.batch; package org.apache.olingo.server.core.deserializer.batch;
import java.util.ArrayList; import java.net.URI;
import java.net.URISyntaxException;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashSet; import java.util.HashSet;
import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import org.apache.olingo.commons.api.http.HttpHeader;
import org.apache.olingo.commons.api.http.HttpMethod; import org.apache.olingo.commons.api.http.HttpMethod;
import org.apache.olingo.server.api.batch.exception.BatchDeserializerException; import org.apache.olingo.server.api.batch.exception.BatchDeserializerException;
import org.apache.olingo.server.api.batch.exception.BatchDeserializerException.MessageKeys; import org.apache.olingo.server.api.batch.exception.BatchDeserializerException.MessageKeys;
public class HttpRequestStatusLine { public class HttpRequestStatusLine {
private static final Pattern PATTERN_RELATIVE_URI = Pattern.compile("([^/][^?]*)(?:\\?(.*))?"); private static final Pattern PATTERN_RELATIVE_URI = Pattern.compile("([^/][^?]*)(?:\\?(.*))?");
private static final Pattern PATTERN_ABSOLUTE_URI_WITH_HOST = Pattern.compile("(/[^?]*)(?:\\?(.*))?");
private static final Pattern PATTERN_ABSOLUTE_URI = Pattern.compile("(http[s]?://[^?]*)(?:\\?(.*))?");
private static final Set<String> HTTP_BATCH_METHODS = new HashSet<String>(Arrays.asList(new String[] { "GET" })); private static final Set<String> HTTP_BATCH_METHODS = new HashSet<String>(Arrays.asList(new String[] { "GET" }));
private static final Set<String> HTTP_CHANGE_SET_METHODS = new HashSet<String>(Arrays.asList(new String[] { "POST", private static final Set<String> HTTP_CHANGE_SET_METHODS = new HashSet<String>(Arrays.asList(new String[] { "POST",
@ -46,15 +43,16 @@ public class HttpRequestStatusLine {
private HttpMethod method; private HttpMethod method;
private String httpVersion; private String httpVersion;
private Header header; private String rawServiceResolutionUri;
private ODataURI uri; private String rawQueryPath;
private String rawODataPath;
private String rawBaseUri;
private String rawRequestUri;
public HttpRequestStatusLine(final Line httpStatusLine, final String baseUri, final String serviceResolutionUri, public HttpRequestStatusLine(final Line httpStatusLine, final String baseUri, final String serviceResolutionUrir)
final Header requestHeader)
throws BatchDeserializerException { throws BatchDeserializerException {
statusLine = httpStatusLine; statusLine = httpStatusLine;
requestBaseUri = baseUri; requestBaseUri = baseUri;
header = requestHeader;
parse(); parse();
} }
@ -64,7 +62,8 @@ public class HttpRequestStatusLine {
if (parts.length == 3) { if (parts.length == 3) {
method = parseMethod(parts[0]); method = parseMethod(parts[0]);
uri = new ODataURI(parts[1], requestBaseUri, statusLine.getLineNumber(), header.getHeaders(HttpHeader.HOST)); // uri = new ODataURI(parts[1], requestBaseUri, statusLine.getLineNumber(), header.getHeaders(HttpHeader.HOST));
parseUri(parts[1], requestBaseUri);
httpVersion = parseHttpVersion(parts[2]); httpVersion = parseHttpVersion(parts[2]);
} else { } else {
throw new BatchDeserializerException("Invalid status line", MessageKeys.INVALID_STATUS_LINE, statusLine throw new BatchDeserializerException("Invalid status line", MessageKeys.INVALID_STATUS_LINE, statusLine
@ -72,6 +71,40 @@ public class HttpRequestStatusLine {
} }
} }
private void parseUri(String rawUri, String baseUrl) throws BatchDeserializerException {
try {
final URI uri = new URI(rawUri);
if (uri.isAbsolute()) {
throw new BatchDeserializerException("Forbidden absolute uri", MessageKeys.FORBIDDEN_ABSOLUTE_URI, statusLine
.getLineNumber());
} else {
final Matcher relativeUriMatcher = PATTERN_RELATIVE_URI.matcher(rawUri);
if (relativeUriMatcher.matches()) {
buildUri(relativeUriMatcher.group(1), relativeUriMatcher.group(2));
} else {
throw new BatchDeserializerException("Malformed uri", MessageKeys.INVALID_URI, statusLine.getLineNumber());
}
}
} catch (URISyntaxException e) {
throw new BatchDeserializerException("Malformed uri", MessageKeys.INVALID_URI, statusLine.getLineNumber());
}
}
private void buildUri(final String oDataPath, final String queryOptions) throws BatchDeserializerException {
rawBaseUri = requestBaseUri;
rawODataPath = "/" + oDataPath;
rawRequestUri = requestBaseUri + rawODataPath;
if (queryOptions != null) {
rawRequestUri += "?" + queryOptions;
rawQueryPath = queryOptions;
} else {
rawQueryPath = "";
}
}
private HttpMethod parseMethod(final String method) throws BatchDeserializerException { private HttpMethod parseMethod(final String method) throws BatchDeserializerException {
try { try {
return HttpMethod.valueOf(method.trim()); return HttpMethod.valueOf(method.trim());
@ -96,8 +129,7 @@ public class HttpRequestStatusLine {
if (!validMethods.contains(getMethod().toString())) { if (!validMethods.contains(getMethod().toString())) {
if (isChangeSet) { if (isChangeSet) {
throw new BatchDeserializerException("Invalid change set method", MessageKeys.INVALID_CHANGESET_METHOD, throw new BatchDeserializerException("Invalid change set method", MessageKeys.INVALID_CHANGESET_METHOD,
statusLine statusLine.getLineNumber());
.getLineNumber());
} else { } else {
throw new BatchDeserializerException("Invalid query operation method", throw new BatchDeserializerException("Invalid query operation method",
MessageKeys.INVALID_QUERY_OPERATION_METHOD, MessageKeys.INVALID_QUERY_OPERATION_METHOD,
@ -118,114 +150,27 @@ public class HttpRequestStatusLine {
return statusLine.getLineNumber(); return statusLine.getLineNumber();
} }
public ODataURI getUri() { public String getRequestBaseUri() {
return uri; return requestBaseUri;
}
public static class ODataURI {
private String rawServiceResolutionUri;
private String rawQueryPath;
private String rawODataPath;
private String rawBaseUri;
private String rawRequestUri;
private final String requestBaseUri;
private final int lineNumber;
public ODataURI(final String rawUri, final String requestBaseUri) throws BatchDeserializerException {
this(rawUri, requestBaseUri, 0, new ArrayList<String>());
}
public ODataURI(final String rawUri, final String requestBaseUri, final int lineNumber,
final List<String> hostHeader)
throws BatchDeserializerException {
this.lineNumber = lineNumber;
this.requestBaseUri = requestBaseUri;
final Matcher absoluteUriMatcher = PATTERN_ABSOLUTE_URI.matcher(rawUri);
final Matcher absoluteUriWtithHostMatcher = PATTERN_ABSOLUTE_URI_WITH_HOST.matcher(rawUri);
final Matcher relativeUriMatcher = PATTERN_RELATIVE_URI.matcher(rawUri);
if (absoluteUriMatcher.matches()) {
buildUri(absoluteUriMatcher.group(1), absoluteUriMatcher.group(2));
} else if (absoluteUriWtithHostMatcher.matches()) {
if (hostHeader != null && hostHeader.size() == 1) {
buildUri(hostHeader.get(0) + absoluteUriWtithHostMatcher.group(1), absoluteUriWtithHostMatcher.group(2));
} else {
throw new BatchDeserializerException("Exactly one host header is required",
MessageKeys.MISSING_MANDATORY_HEADER,
lineNumber);
}
} else if (relativeUriMatcher.matches()) {
buildUri(requestBaseUri + "/" + relativeUriMatcher.group(1), relativeUriMatcher.group(2));
} else {
throw new BatchDeserializerException("Invalid uri", MessageKeys.INVALID_URI, lineNumber);
}
}
private void buildUri(final String resourceUri, final String queryOptions) throws BatchDeserializerException {
if (!resourceUri.startsWith(requestBaseUri)) {
throw new BatchDeserializerException("Host do not match", MessageKeys.INVALID_URI, lineNumber);
}
final int oDataPathIndex = resourceUri.indexOf(requestBaseUri);
rawBaseUri = requestBaseUri;
rawODataPath = resourceUri.substring(oDataPathIndex + requestBaseUri.length());
rawRequestUri = requestBaseUri + rawODataPath;
if (queryOptions != null) {
rawRequestUri += "?" + queryOptions;
rawQueryPath = queryOptions;
} else {
rawQueryPath = "";
}
} }
public String getRawServiceResolutionUri() { public String getRawServiceResolutionUri() {
return rawServiceResolutionUri; return rawServiceResolutionUri;
} }
public void setRawServiceResolutionUri(final String rawServiceResolutionUri) {
this.rawServiceResolutionUri = rawServiceResolutionUri;
}
public String getRawQueryPath() { public String getRawQueryPath() {
return rawQueryPath; return rawQueryPath;
} }
public void setRawQueryPath(final String rawQueryPath) {
this.rawQueryPath = rawQueryPath;
}
public String getRawODataPath() { public String getRawODataPath() {
return rawODataPath; return rawODataPath;
} }
public void setRawODataPath(final String rawODataPath) {
this.rawODataPath = rawODataPath;
}
public String getRawBaseUri() { public String getRawBaseUri() {
return rawBaseUri; return rawBaseUri;
} }
public void setRawBaseUri(final String rawBaseUri) {
this.rawBaseUri = rawBaseUri;
}
public String getRawRequestUri() { public String getRawRequestUri() {
return rawRequestUri; return rawRequestUri;
} }
public void setRawRequestUri(final String rawRequestUri) {
this.rawRequestUri = rawRequestUri;
}
public String getRequestBaseUri() {
return requestBaseUri;
}
}
} }

View File

@ -116,5 +116,6 @@ BatchDeserializerException.MISSING_CONTENT_ID=Missing content-id at line '%1$s'.
BatchDeserializerException.MISSING_CONTENT_TRANSFER_ENCODING=Missing content transfer encoding at line '%1$s'. BatchDeserializerException.MISSING_CONTENT_TRANSFER_ENCODING=Missing content transfer encoding at line '%1$s'.
BatchDeserializerException.MISSING_CONTENT_TYPE=Missing content-type at line '%1$s'. BatchDeserializerException.MISSING_CONTENT_TYPE=Missing content-type at line '%1$s'.
BatchDeserializerException.MISSING_MANDATORY_HEADER=Missing mandatory header at line '%1$s'. BatchDeserializerException.MISSING_MANDATORY_HEADER=Missing mandatory header at line '%1$s'.
BatchDeserializerException.FORBIDDEN_ABSOLUTE_URI=Forbidden absolute request URI at line '%1$s'.
BatchSerializerExecption.MISSING_CONTENT_ID=Each request within a change set required exactly one content id. BatchSerializerExecption.MISSING_CONTENT_ID=Each request within a change set required exactly one content id.

View File

@ -89,7 +89,7 @@ public class MockedBatchHandlerTest {
+ "Content-Transfer-Encoding: binary" + CRLF + "Content-Transfer-Encoding: binary" + CRLF
+ "Content-Id: 3" + CRLF + "Content-Id: 3" + CRLF
+ CRLF + CRLF
+ "PUT ESAllPrim(1) HTTP/1.1" + CRLF // Relative URI + "PUT ESAllPrim(1) HTTP/1.1" + CRLF
+ "Content-Type: application/json;odata=verbose" + CRLF + "Content-Type: application/json;odata=verbose" + CRLF
+ CRLF + CRLF
+ CRLF + CRLF
@ -98,8 +98,7 @@ public class MockedBatchHandlerTest {
+ "Content-Transfer-Encoding: binary" + CRLF + "Content-Transfer-Encoding: binary" + CRLF
+ "Content-Id: 4" + CRLF + "Content-Id: 4" + CRLF
+ CRLF + CRLF
+ "PUT /$3/PropertyInt32 HTTP/1.1" + CRLF // Absolute URI with separate Host header and ref. + "PUT $3/PropertyInt32 HTTP/1.1" + CRLF
+ "Host: http://localhost:8080/odata" + CRLF
+ "Content-Type: application/json;odata=verbose" + CRLF + "Content-Type: application/json;odata=verbose" + CRLF
+ CRLF + CRLF
+ CRLF + CRLF
@ -108,7 +107,7 @@ public class MockedBatchHandlerTest {
+ "Content-Transfer-Encoding: binary" + CRLF + "Content-Transfer-Encoding: binary" + CRLF
+ "Content-Id: 1" + CRLF + "Content-Id: 1" + CRLF
+ CRLF + CRLF
+ "POST http://localhost:8080/odata/ESAllPrim HTTP/1.1" + CRLF // Absolute URI + "POST ESAllPrim HTTP/1.1" + CRLF
+ "Content-Type: application/json;odata=verbose" + CRLF + "Content-Type: application/json;odata=verbose" + CRLF
+ CRLF + CRLF
+ CRLF + CRLF
@ -117,7 +116,7 @@ public class MockedBatchHandlerTest {
+ "Content-Transfer-Encoding: binary" + CRLF + "Content-Transfer-Encoding: binary" + CRLF
+ "Content-Id: 5" + CRLF + "Content-Id: 5" + CRLF
+ CRLF + CRLF
+ "POST http://localhost:8080/odata/$1/NavPropertyETTwoPrimMany HTTP/1.1" + CRLF // Absolute URI with ref. + "POST $1/NavPropertyETTwoPrimMany HTTP/1.1" + CRLF
+ "Content-Type: application/json;odata=verbose" + CRLF + "Content-Type: application/json;odata=verbose" + CRLF
+ CRLF + CRLF
+ CRLF + CRLF
@ -126,7 +125,7 @@ public class MockedBatchHandlerTest {
+ "Content-Transfer-Encoding: binary" + CRLF + "Content-Transfer-Encoding: binary" + CRLF
+ "Content-Id: 2" + CRLF + "Content-Id: 2" + CRLF
+ CRLF + CRLF
+ "POST $1/NavPropertyETTwoPrimMany HTTP/1.1" + CRLF // Relative URI with ref. + "POST $1/NavPropertyETTwoPrimMany HTTP/1.1" + CRLF
+ "Content-Type: application/json;odata=verbose" + CRLF + "Content-Type: application/json;odata=verbose" + CRLF
+ CRLF + CRLF
+ CRLF + CRLF
@ -135,8 +134,7 @@ public class MockedBatchHandlerTest {
+ "Content-Transfer-Encoding: binary" + CRLF + "Content-Transfer-Encoding: binary" + CRLF
+ "Content-Id: 6" + CRLF + "Content-Id: 6" + CRLF
+ CRLF + CRLF
+ "PUT /ESAllPrim(1) HTTP/1.1" + CRLF // Absolute URI with separate Host header + "PUT ESAllPrim(1) HTTP/1.1" + CRLF
+ "Host: http://localhost:8080/odata"
+ "Content-Type: application/json;odata=verbose" + CRLF + "Content-Type: application/json;odata=verbose" + CRLF
+ CRLF + CRLF
+ CRLF + CRLF
@ -264,8 +262,7 @@ public class MockedBatchHandlerTest {
+ "Content-Transfer-Encoding: binary" + CRLF + "Content-Transfer-Encoding: binary" + CRLF
+ "Content-Id: 2" + CRLF + "Content-Id: 2" + CRLF
+ CRLF + CRLF
+ "POST /$1/NavPropertyETTwoPrimMany HTTP/1.1" + CRLF + "POST $1/NavPropertyETTwoPrimMany HTTP/1.1" + CRLF
+ "Host: http://localhost:8080/odata" + CRLF
+ "Content-Type: application/json;odata=verbose" + CRLF + "Content-Type: application/json;odata=verbose" + CRLF
+ CRLF + CRLF
+ CRLF + CRLF
@ -288,8 +285,7 @@ public class MockedBatchHandlerTest {
+ "Content-Transfer-Encoding: binary" + CRLF + "Content-Transfer-Encoding: binary" + CRLF
+ "Content-Id: 2" + CRLF + "Content-Id: 2" + CRLF
+ CRLF + CRLF
+ "POST /$1/NavPropertyETTwoPrimMany HTTP/1.1" + CRLF + "POST $1/NavPropertyETTwoPrimMany HTTP/1.1" + CRLF
+ "Host: http://localhost:8080/odata" + CRLF
+ "Content-Type: application/json;odata=verbose" + CRLF + "Content-Type: application/json;odata=verbose" + CRLF
+ CRLF + CRLF
+ CRLF + CRLF
@ -390,8 +386,7 @@ public class MockedBatchHandlerTest {
+ "Content-Transfer-Encoding: binary" + CRLF + "Content-Transfer-Encoding: binary" + CRLF
+ "Content-Id: 2" + CRLF + "Content-Id: 2" + CRLF
+ CRLF + CRLF
+ "POST /$1/NavPropertyETTwoPrimMany HTTP/1.1" + CRLF + "POST $1/NavPropertyETTwoPrimMany HTTP/1.1" + CRLF
+ "Host: http://localhost:8080/odata" + CRLF
+ "Content-Type: application/json;odata=verbose" + CRLF + "Content-Type: application/json;odata=verbose" + CRLF
+ CRLF + CRLF
+ CRLF + CRLF

View File

@ -602,7 +602,7 @@ public class BatchRequestParserTest {
} }
@Test @Test
public void testInvalidUri() throws Exception { public void testAbsoluteUri() throws Exception {
final String batch = "" final String batch = ""
+ "--batch_8194-cf13-1f56" + CRLF + "--batch_8194-cf13-1f56" + CRLF
+ MIME_HEADERS + MIME_HEADERS
@ -612,7 +612,7 @@ public class BatchRequestParserTest {
+ CRLF + CRLF
+ "--batch_8194-cf13-1f56--"; + "--batch_8194-cf13-1f56--";
parseInvalidBatchBody(batch, BatchDeserializerException.MessageKeys.INVALID_URI); parseInvalidBatchBody(batch, BatchDeserializerException.MessageKeys.FORBIDDEN_ABSOLUTE_URI);
} }
@Test @Test
@ -627,17 +627,7 @@ public class BatchRequestParserTest {
+ CRLF + CRLF
+ "--batch_8194-cf13-1f56--"; + "--batch_8194-cf13-1f56--";
final List<BatchRequestPart> parts = parse(batch); parseInvalidBatchBody(batch, BatchDeserializerException.MessageKeys.INVALID_URI);
assertEquals(1, parts.size());
final BatchRequestPart part = parts.get(0);
assertEquals(1, part.getRequests().size());
final ODataRequest request = part.getRequests().get(0);
assertEquals("http://localhost/odata/Employees('1')/EmployeeName", request.getRawRequestUri());
assertEquals("http://localhost/odata", request.getRawBaseUri());
assertEquals("/Employees('1')/EmployeeName", request.getRawODataPath());
assertEquals("", request.getRawQueryPath());
} }
@Test @Test
@ -651,23 +641,7 @@ public class BatchRequestParserTest {
+ CRLF + CRLF
+ "--batch_8194-cf13-1f56--"; + "--batch_8194-cf13-1f56--";
parseInvalidBatchBody(batch, MessageKeys.MISSING_MANDATORY_HEADER); parseInvalidBatchBody(batch, MessageKeys.INVALID_URI);
}
@Test
public void testUriWithAbsolutePathMissingHostDulpicatedHeader() throws Exception {
final String batch = ""
+ "--batch_8194-cf13-1f56" + CRLF
+ MIME_HEADERS
+ CRLF
+ "GET /odata/Employees('1')/EmployeeName HTTP/1.1" + CRLF
+ "Host: http://localhost" + CRLF
+ "Host: http://localhost/odata" + CRLF
+ CRLF
+ CRLF
+ "--batch_8194-cf13-1f56--";
parseInvalidBatchBody(batch, MessageKeys.MISSING_MANDATORY_HEADER);
} }
@Test @Test

View File

@ -2,7 +2,7 @@
Content-Type: application/http Content-Type: application/http
Content-Transfer-Encoding: binary Content-Transfer-Encoding: binary
GET http://localhost/odata/Employees('2')/EmployeeName?$format=json HTTP/1.1 GET Employees('2')/EmployeeName?$format=json HTTP/1.1
Accept: application/atomsvc+xml;q=0.8, application/json;odata=verbose;q=0.5, */*;q=0.1 Accept: application/atomsvc+xml;q=0.8, application/json;odata=verbose;q=0.5, */*;q=0.1
Accept-Language:en-US,en;q=0.7,en-UK;q=0.9 Accept-Language:en-US,en;q=0.7,en-UK;q=0.9
MaxDataServiceVersion: 2.0 MaxDataServiceVersion: 2.0