From 297950a8d0d577d99acdac8ed42d09129a65add7 Mon Sep 17 00:00:00 2001 From: Christian Holzer Date: Mon, 1 Dec 2014 17:18:05 +0100 Subject: [PATCH] [OLINGO-472] Absolute Uris are not longer allowed Signed-off-by: Christian Amend --- .../fit/tecsvc/client/BatchClientITCase.java | 7 +- .../olingo/client/api/CommonODataClient.java | 4 +- .../olingo/client/api/Configuration.java | 16 +- .../olingo/client/api/uri/UriFormat.java | 38 ++++ .../olingo/client/api/v3/ODataClient.java | 5 +- .../olingo/client/api/v4/ODataClient.java | 5 +- .../olingo/client/core/ConfigurationImpl.java | 13 ++ .../client/core/uri/AbstractURIBuilder.java | 41 ++-- .../core/uri/v3/BatchURIBuilderImpl.java | 35 ++++ .../core/uri/v4/BatchURIBuilderImpl.java | 36 ++++ .../client/core/v3/ODataClientImpl.java | 8 +- .../client/core/v4/ODataClientImpl.java | 8 +- .../exception/BatchDeserializerException.java | 3 +- .../BatchReferenceRewriter.java | 15 +- .../batch/BatchRequestTransformator.java | 15 +- .../batch/HttpRequestStatusLine.java | 183 ++++++------------ .../server-core-exceptions-i18n.properties | 1 + .../batchhandler/MockedBatchHandlerTest.java | 23 +-- .../deserializer/BatchRequestParserTest.java | 34 +--- .../src/test/resources/batchWithPost.batch | 2 +- 20 files changed, 287 insertions(+), 205 deletions(-) create mode 100644 lib/client-api/src/main/java/org/apache/olingo/client/api/uri/UriFormat.java create mode 100644 lib/client-core/src/main/java/org/apache/olingo/client/core/uri/v3/BatchURIBuilderImpl.java create mode 100644 lib/client-core/src/main/java/org/apache/olingo/client/core/uri/v4/BatchURIBuilderImpl.java diff --git a/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/BatchClientITCase.java b/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/BatchClientITCase.java index 3d6fba939..1ba00d574 100644 --- a/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/BatchClientITCase.java +++ b/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/BatchClientITCase.java @@ -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.ODataEntityUpdateResponse; 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.core.communication.request.batch.ODataChangesetResponseItem; import org.apache.olingo.client.core.uri.URIUtils; @@ -65,6 +66,7 @@ public class BatchClientITCase extends AbstractTestITCase { @Before public void setup() { client.getConfiguration().setContinueOnError(false); + client.getConfiguration().setBatchUriFormat(UriFormat.RELATIVE); } @Test @@ -162,7 +164,6 @@ public class BatchClientITCase extends AbstractTestITCase { @Test public void testErrorWithContinueOnErrorPreferHeader() { client.getConfiguration().setContinueOnError(true); - final ODataBatchRequest request = client.getBatchRequestFactory().getBatchRequest(SERVICE_URI); request.setAccept(ACCEPT); @@ -446,9 +447,9 @@ public class BatchClientITCase extends AbstractTestITCase { } 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); - + ODataEntityRequest queryReq = client.getRetrieveRequestFactory().getEntityRequest(targetURI.build()); queryReq.setFormat(ODataFormat.JSON); manager.addRequest(queryReq); diff --git a/lib/client-api/src/main/java/org/apache/olingo/client/api/CommonODataClient.java b/lib/client-api/src/main/java/org/apache/olingo/client/api/CommonODataClient.java index 336fa6fb9..7d8efbe92 100644 --- a/lib/client-api/src/main/java/org/apache/olingo/client/api/CommonODataClient.java +++ b/lib/client-api/src/main/java/org/apache/olingo/client/api/CommonODataClient.java @@ -52,7 +52,9 @@ public interface CommonODataClient { ODataPreferences newPreferences(); CommonURIBuilder newURIBuilder(String serviceRoot); - + + CommonURIBuilder newBatchURIBuilder(String serviceRoot); + CommonFilterFactory getFilterFactory(); ODataSerializer getSerializer(ODataFormat format); diff --git a/lib/client-api/src/main/java/org/apache/olingo/client/api/Configuration.java b/lib/client-api/src/main/java/org/apache/olingo/client/api/Configuration.java index 2dcc05914..9fedc565f 100644 --- a/lib/client-api/src/main/java/org/apache/olingo/client/api/Configuration.java +++ b/lib/client-api/src/main/java/org/apache/olingo/client/api/Configuration.java @@ -22,6 +22,7 @@ import java.util.concurrent.ExecutorService; import org.apache.olingo.client.api.http.HttpClientFactory; 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.ODataFormat; @@ -269,5 +270,18 @@ public interface Configuration { * @param executorService new executor services. */ 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); } diff --git a/lib/client-api/src/main/java/org/apache/olingo/client/api/uri/UriFormat.java b/lib/client-api/src/main/java/org/apache/olingo/client/api/uri/UriFormat.java new file mode 100644 index 000000000..242d21464 --- /dev/null +++ b/lib/client-api/src/main/java/org/apache/olingo/client/api/uri/UriFormat.java @@ -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; +} diff --git a/lib/client-api/src/main/java/org/apache/olingo/client/api/v3/ODataClient.java b/lib/client-api/src/main/java/org/apache/olingo/client/api/v3/ODataClient.java index 4e8acb136..b45becd86 100644 --- a/lib/client-api/src/main/java/org/apache/olingo/client/api/v3/ODataClient.java +++ b/lib/client-api/src/main/java/org/apache/olingo/client/api/v3/ODataClient.java @@ -44,7 +44,10 @@ public interface ODataClient extends CommonODataClient { @Override URIBuilder newURIBuilder(String serviceRoot); - + + @Override + URIBuilder newBatchURIBuilder(String serviceRoot); + @Override FilterFactory getFilterFactory(); diff --git a/lib/client-api/src/main/java/org/apache/olingo/client/api/v4/ODataClient.java b/lib/client-api/src/main/java/org/apache/olingo/client/api/v4/ODataClient.java index 2c9ba9086..ed6ecf5db 100644 --- a/lib/client-api/src/main/java/org/apache/olingo/client/api/v4/ODataClient.java +++ b/lib/client-api/src/main/java/org/apache/olingo/client/api/v4/ODataClient.java @@ -46,7 +46,10 @@ public interface ODataClient extends CommonODataClient { @Override URIBuilder newURIBuilder(String serviceRoot); - + + @Override + URIBuilder newBatchURIBuilder(String serviceRoot); + @Override FilterFactory getFilterFactory(); diff --git a/lib/client-core/src/main/java/org/apache/olingo/client/core/ConfigurationImpl.java b/lib/client-core/src/main/java/org/apache/olingo/client/core/ConfigurationImpl.java index cd17ad0d4..0385878ad 100644 --- a/lib/client-core/src/main/java/org/apache/olingo/client/core/ConfigurationImpl.java +++ b/lib/client-core/src/main/java/org/apache/olingo/client/core/ConfigurationImpl.java @@ -26,6 +26,7 @@ import java.util.concurrent.Executors; import org.apache.olingo.client.api.Configuration; import org.apache.olingo.client.api.http.HttpClientFactory; 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.DefaultHttpUriRequestFactory; 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 BATCH_URI_FORMAT = "batchUriFormat"; + private final Map CONF = new HashMap(); private transient ExecutorService executor = Executors.newFixedThreadPool(10); @@ -230,4 +233,14 @@ public class ConfigurationImpl implements Configuration { public void setExecutor(final ExecutorService 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); + } } diff --git a/lib/client-core/src/main/java/org/apache/olingo/client/core/uri/AbstractURIBuilder.java b/lib/client-core/src/main/java/org/apache/olingo/client/core/uri/AbstractURIBuilder.java index f865f47cc..07153ad87 100644 --- a/lib/client-core/src/main/java/org/apache/olingo/client/core/uri/AbstractURIBuilder.java +++ b/lib/client-core/src/main/java/org/apache/olingo/client/core/uri/AbstractURIBuilder.java @@ -1,18 +1,18 @@ /* * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file + * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file + * 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 - * + * 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 + * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ @@ -62,6 +62,7 @@ public abstract class AbstractURIBuilder> impleme return value; } } + /** * Logger. */ @@ -90,10 +91,11 @@ public abstract class AbstractURIBuilder> impleme * service. */ protected AbstractURIBuilder( - final ODataServiceVersion version, final Configuration configuration, final String serviceRoot) { + final ODataServiceVersion version, final Configuration configuration, final String serviceRoot) { this.version = version; this.configuration = configuration; + segments.add(new Segment(SegmentType.SERVICEROOT, serviceRoot)); } @@ -137,8 +139,8 @@ public abstract class AbstractURIBuilder> impleme final String segValue = URIUtils.escape(version, val); segments.add(configuration.isKeyAsSegment() - ? new Segment(SegmentType.KEY_AS_SEGMENT, segValue) - : new Segment(SegmentType.KEY, "(" + segValue + ")")); + ? new Segment(SegmentType.KEY_AS_SEGMENT, segValue) + : new Segment(SegmentType.KEY, "(" + segValue + ")")); return getThis(); } @@ -187,7 +189,7 @@ public abstract class AbstractURIBuilder> impleme @Override public UB appendOperationCallSegment(final String operation) { segments.add(new Segment( - segments.size() == 1 ? SegmentType.UNBOUND_OPERATION : SegmentType.BOUND_OPERATION, operation)); + segments.size() == 1 ? SegmentType.UNBOUND_OPERATION : SegmentType.BOUND_OPERATION, operation)); return getThis(); } @@ -268,17 +270,18 @@ public abstract class AbstractURIBuilder> impleme @Override public URI build() { final StringBuilder segmentsBuilder = new StringBuilder(); + for (Segment seg : segments) { if (segmentsBuilder.length() > 0 && seg.getType() != SegmentType.KEY) { switch (seg.getType()) { - case BOUND_OPERATION: - segmentsBuilder.append(getBoundOperationSeparator()); - break; + case BOUND_OPERATION: + segmentsBuilder.append(getBoundOperationSeparator()); + break; - default: - if (segmentsBuilder.length() > 0 && segmentsBuilder.charAt(segmentsBuilder.length() - 1) != '/') { - segmentsBuilder.append('/'); - } + default: + if (segmentsBuilder.length() > 0 && segmentsBuilder.charAt(segmentsBuilder.length() - 1) != '/') { + segmentsBuilder.append('/'); + } } } @@ -330,7 +333,7 @@ public abstract class AbstractURIBuilder> impleme final StringBuilder keyBuilder = new StringBuilder().append('('); for (Map.Entry entry : segmentValues.entrySet()) { keyBuilder.append(entry.getKey()).append('=').append( - escape ? URIUtils.escape(version, entry.getValue()) : entry.getValue()); + escape ? URIUtils.escape(version, entry.getValue()) : entry.getValue()); keyBuilder.append(','); } keyBuilder.deleteCharAt(keyBuilder.length() - 1).append(')'); diff --git a/lib/client-core/src/main/java/org/apache/olingo/client/core/uri/v3/BatchURIBuilderImpl.java b/lib/client-core/src/main/java/org/apache/olingo/client/core/uri/v3/BatchURIBuilderImpl.java new file mode 100644 index 000000000..3a860fb78 --- /dev/null +++ b/lib/client-core/src/main/java/org/apache/olingo/client/core/uri/v3/BatchURIBuilderImpl.java @@ -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); + } + } +} diff --git a/lib/client-core/src/main/java/org/apache/olingo/client/core/uri/v4/BatchURIBuilderImpl.java b/lib/client-core/src/main/java/org/apache/olingo/client/core/uri/v4/BatchURIBuilderImpl.java new file mode 100644 index 000000000..e5d725da7 --- /dev/null +++ b/lib/client-core/src/main/java/org/apache/olingo/client/core/uri/v4/BatchURIBuilderImpl.java @@ -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); + } + } + +} diff --git a/lib/client-core/src/main/java/org/apache/olingo/client/core/v3/ODataClientImpl.java b/lib/client-core/src/main/java/org/apache/olingo/client/core/v3/ODataClientImpl.java index caaf423ec..470fc9da4 100644 --- a/lib/client-core/src/main/java/org/apache/olingo/client/core/v3/ODataClientImpl.java +++ b/lib/client-core/src/main/java/org/apache/olingo/client/core/v3/ODataClientImpl.java @@ -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.ODataDeserializerImpl; 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.URIBuilderImpl; import org.apache.olingo.commons.api.domain.v3.ODataObjectFactory; @@ -86,7 +87,12 @@ public class ODataClientImpl extends AbstractODataClient implements public URIBuilder newURIBuilder(final String serviceRoot) { return new URIBuilderImpl(getServiceVersion(), configuration, serviceRoot); } - + + @Override + public URIBuilder newBatchURIBuilder(String serviceRoot) { + return new BatchURIBuilderImpl(getServiceVersion(), getConfiguration(), serviceRoot); + } + @Override public FilterFactory getFilterFactory() { return filterFactory; diff --git a/lib/client-core/src/main/java/org/apache/olingo/client/core/v4/ODataClientImpl.java b/lib/client-core/src/main/java/org/apache/olingo/client/core/v4/ODataClientImpl.java index c1a4f1df7..29f0b4206 100644 --- a/lib/client-core/src/main/java/org/apache/olingo/client/core/v4/ODataClientImpl.java +++ b/lib/client-core/src/main/java/org/apache/olingo/client/core/v4/ODataClientImpl.java @@ -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.ODataDeserializerImpl; 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.URIBuilderImpl; import org.apache.olingo.commons.api.domain.v4.ODataObjectFactory; @@ -92,7 +93,12 @@ public class ODataClientImpl extends AbstractODataClient implements public URIBuilder newURIBuilder(final String serviceRoot) { return new URIBuilderImpl(getServiceVersion(), getConfiguration(), serviceRoot); } - + + @Override + public URIBuilder newBatchURIBuilder(String serviceRoot) { + return new BatchURIBuilderImpl(getServiceVersion(), getConfiguration(), serviceRoot); + } + @Override public FilterFactory getFilterFactory() { return filterFactory; diff --git a/lib/server-api/src/main/java/org/apache/olingo/server/api/batch/exception/BatchDeserializerException.java b/lib/server-api/src/main/java/org/apache/olingo/server/api/batch/exception/BatchDeserializerException.java index 48f381583..060d47595 100644 --- a/lib/server-api/src/main/java/org/apache/olingo/server/api/batch/exception/BatchDeserializerException.java +++ b/lib/server-api/src/main/java/org/apache/olingo/server/api/batch/exception/BatchDeserializerException.java @@ -39,7 +39,8 @@ public class BatchDeserializerException extends BatchException { MISSING_CONTENT_TRANSFER_ENCODING, MISSING_CONTENT_TYPE, MISSING_MANDATORY_HEADER, - FORBIDDEN_HEADER; + FORBIDDEN_HEADER, + FORBIDDEN_ABSOLUTE_URI; @Override public String getKey() { diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/batchhandler/referenceRewriting/BatchReferenceRewriter.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/batchhandler/referenceRewriting/BatchReferenceRewriter.java index 195dca79b..772fd9d05 100644 --- a/lib/server-core/src/main/java/org/apache/olingo/server/core/batchhandler/referenceRewriting/BatchReferenceRewriter.java +++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/batchhandler/referenceRewriting/BatchReferenceRewriter.java @@ -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.ODataResponse; 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.HttpRequestStatusLine.ODataURI; public class BatchReferenceRewriter { private static final String REG_EX_REFERENCE = "\\$(.*)(/.*)?"; @@ -78,8 +78,7 @@ public class BatchReferenceRewriter { if (request.getMethod() == HttpMethod.POST) { // Create entity // 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 = uri.getRawODataPath(); + resourceUri = parseODataPath(response.getHeaders().get(HttpHeader.LOCATION), request.getRawBaseUri()); } else { // Update, Upsert (PUT, PATCH, Delete) // 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; } + 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) { final int indexOfSlash = rawODataPath.indexOf("/"); if (first) { diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/batch/BatchRequestTransformator.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/batch/BatchRequestTransformator.java index 3c5fd36c9..6da8de83b 100644 --- a/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/batch/BatchRequestTransformator.java +++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/batch/BatchRequestTransformator.java @@ -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.MessageKeys; import org.apache.olingo.server.api.deserializer.batch.BatchRequestPart; -import org.apache.olingo.server.core.deserializer.batch.HttpRequestStatusLine.ODataURI; public class BatchRequestTransformator { private final String baseUri; @@ -101,10 +100,8 @@ public class BatchRequestTransformator { final boolean isChangeSet) throws BatchDeserializerException { final HttpRequestStatusLine statusLine = - new HttpRequestStatusLine(operation.getHttpStatusLine(), baseUri, rawServiceResolutionUri, operation - .getHeaders()); + new HttpRequestStatusLine(operation.getHttpStatusLine(), baseUri, rawServiceResolutionUri); statusLine.validateHttpMethod(isChangeSet); - final ODataURI uri = statusLine.getUri(); validateBody(statusLine, operation); InputStream bodyStrean = getBodyStream(operation, statusLine); @@ -114,11 +111,11 @@ public class BatchRequestTransformator { final ODataRequest request = new ODataRequest(); request.setBody(bodyStrean); request.setMethod(statusLine.getMethod()); - request.setRawBaseUri(uri.getRawBaseUri()); - request.setRawODataPath(uri.getRawODataPath()); - request.setRawQueryPath(uri.getRawQueryPath()); - request.setRawRequestUri(uri.getRawRequestUri()); - request.setRawServiceResolutionUri(uri.getRawServiceResolutionUri()); + request.setRawBaseUri(statusLine.getRawBaseUri()); + request.setRawODataPath(statusLine.getRawODataPath()); + request.setRawQueryPath(statusLine.getRawQueryPath()); + request.setRawRequestUri(statusLine.getRawRequestUri()); + request.setRawServiceResolutionUri(statusLine.getRawServiceResolutionUri()); for (final HeaderField field : operation.getHeaders()) { request.addHeader(field.getFieldName(), field.getValues()); diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/batch/HttpRequestStatusLine.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/batch/HttpRequestStatusLine.java index 1e52ebc82..36b18a879 100644 --- a/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/batch/HttpRequestStatusLine.java +++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/batch/HttpRequestStatusLine.java @@ -6,9 +6,9 @@ * 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 @@ -18,23 +18,20 @@ */ 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.HashSet; -import java.util.List; import java.util.Set; import java.util.regex.Matcher; 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.server.api.batch.exception.BatchDeserializerException; import org.apache.olingo.server.api.batch.exception.BatchDeserializerException.MessageKeys; public class HttpRequestStatusLine { 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 HTTP_BATCH_METHODS = new HashSet(Arrays.asList(new String[] { "GET" })); private static final Set HTTP_CHANGE_SET_METHODS = new HashSet(Arrays.asList(new String[] { "POST", @@ -46,15 +43,16 @@ public class HttpRequestStatusLine { private HttpMethod method; private String httpVersion; - private Header header; - private ODataURI uri; + private String rawServiceResolutionUri; + private String rawQueryPath; + private String rawODataPath; + private String rawBaseUri; + private String rawRequestUri; - public HttpRequestStatusLine(final Line httpStatusLine, final String baseUri, final String serviceResolutionUri, - final Header requestHeader) - throws BatchDeserializerException { + public HttpRequestStatusLine(final Line httpStatusLine, final String baseUri, final String serviceResolutionUrir) + throws BatchDeserializerException { statusLine = httpStatusLine; requestBaseUri = baseUri; - header = requestHeader; parse(); } @@ -64,7 +62,8 @@ public class HttpRequestStatusLine { if (parts.length == 3) { 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]); } else { 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 { try { return HttpMethod.valueOf(method.trim()); @@ -96,8 +129,7 @@ public class HttpRequestStatusLine { if (!validMethods.contains(getMethod().toString())) { if (isChangeSet) { throw new BatchDeserializerException("Invalid change set method", MessageKeys.INVALID_CHANGESET_METHOD, - statusLine - .getLineNumber()); + statusLine.getLineNumber()); } else { throw new BatchDeserializerException("Invalid query operation method", MessageKeys.INVALID_QUERY_OPERATION_METHOD, @@ -118,114 +150,27 @@ public class HttpRequestStatusLine { return statusLine.getLineNumber(); } - public ODataURI getUri() { - return uri; + public String getRequestBaseUri() { + 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 String getRawServiceResolutionUri() { + return rawServiceResolutionUri; + } - public ODataURI(final String rawUri, final String requestBaseUri) throws BatchDeserializerException { - this(rawUri, requestBaseUri, 0, new ArrayList()); - } + public String getRawQueryPath() { + return rawQueryPath; + } - public ODataURI(final String rawUri, final String requestBaseUri, final int lineNumber, - final List hostHeader) - throws BatchDeserializerException { - this.lineNumber = lineNumber; - this.requestBaseUri = requestBaseUri; + public String getRawODataPath() { + return rawODataPath; + } - 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); + public String getRawBaseUri() { + return rawBaseUri; + } - 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() { - return rawServiceResolutionUri; - } - - public void setRawServiceResolutionUri(final String rawServiceResolutionUri) { - this.rawServiceResolutionUri = rawServiceResolutionUri; - } - - public String getRawQueryPath() { - return rawQueryPath; - } - - public void setRawQueryPath(final String rawQueryPath) { - this.rawQueryPath = rawQueryPath; - } - - public String getRawODataPath() { - return rawODataPath; - } - - public void setRawODataPath(final String rawODataPath) { - this.rawODataPath = rawODataPath; - } - - public String getRawBaseUri() { - return rawBaseUri; - } - - public void setRawBaseUri(final String rawBaseUri) { - this.rawBaseUri = rawBaseUri; - } - - public String getRawRequestUri() { - return rawRequestUri; - } - - public void setRawRequestUri(final String rawRequestUri) { - this.rawRequestUri = rawRequestUri; - } - - public String getRequestBaseUri() { - return requestBaseUri; - } + public String getRawRequestUri() { + return rawRequestUri; } } \ No newline at end of file diff --git a/lib/server-core/src/main/resources/server-core-exceptions-i18n.properties b/lib/server-core/src/main/resources/server-core-exceptions-i18n.properties index 296d55403..ebba20175 100644 --- a/lib/server-core/src/main/resources/server-core-exceptions-i18n.properties +++ b/lib/server-core/src/main/resources/server-core-exceptions-i18n.properties @@ -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_TYPE=Missing content-type 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. \ No newline at end of file diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/batchhandler/MockedBatchHandlerTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/batchhandler/MockedBatchHandlerTest.java index b2f5a2b42..3ba07148c 100644 --- a/lib/server-core/src/test/java/org/apache/olingo/server/core/batchhandler/MockedBatchHandlerTest.java +++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/batchhandler/MockedBatchHandlerTest.java @@ -89,7 +89,7 @@ public class MockedBatchHandlerTest { + "Content-Transfer-Encoding: binary" + CRLF + "Content-Id: 3" + 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 + CRLF + CRLF @@ -98,8 +98,7 @@ public class MockedBatchHandlerTest { + "Content-Transfer-Encoding: binary" + CRLF + "Content-Id: 4" + CRLF + CRLF - + "PUT /$3/PropertyInt32 HTTP/1.1" + CRLF // Absolute URI with separate Host header and ref. - + "Host: http://localhost:8080/odata" + CRLF + + "PUT $3/PropertyInt32 HTTP/1.1" + CRLF + "Content-Type: application/json;odata=verbose" + CRLF + CRLF + CRLF @@ -108,7 +107,7 @@ public class MockedBatchHandlerTest { + "Content-Transfer-Encoding: binary" + CRLF + "Content-Id: 1" + 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 + CRLF + CRLF @@ -117,7 +116,7 @@ public class MockedBatchHandlerTest { + "Content-Transfer-Encoding: binary" + CRLF + "Content-Id: 5" + 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 + CRLF + CRLF @@ -126,7 +125,7 @@ public class MockedBatchHandlerTest { + "Content-Transfer-Encoding: binary" + CRLF + "Content-Id: 2" + 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 + CRLF + CRLF @@ -135,8 +134,7 @@ public class MockedBatchHandlerTest { + "Content-Transfer-Encoding: binary" + CRLF + "Content-Id: 6" + CRLF + CRLF - + "PUT /ESAllPrim(1) HTTP/1.1" + CRLF // Absolute URI with separate Host header - + "Host: http://localhost:8080/odata" + + "PUT ESAllPrim(1) HTTP/1.1" + CRLF + "Content-Type: application/json;odata=verbose" + CRLF + CRLF + CRLF @@ -264,8 +262,7 @@ public class MockedBatchHandlerTest { + "Content-Transfer-Encoding: binary" + CRLF + "Content-Id: 2" + CRLF + CRLF - + "POST /$1/NavPropertyETTwoPrimMany HTTP/1.1" + CRLF - + "Host: http://localhost:8080/odata" + CRLF + + "POST $1/NavPropertyETTwoPrimMany HTTP/1.1" + CRLF + "Content-Type: application/json;odata=verbose" + CRLF + CRLF + CRLF @@ -288,8 +285,7 @@ public class MockedBatchHandlerTest { + "Content-Transfer-Encoding: binary" + CRLF + "Content-Id: 2" + CRLF + CRLF - + "POST /$1/NavPropertyETTwoPrimMany HTTP/1.1" + CRLF - + "Host: http://localhost:8080/odata" + CRLF + + "POST $1/NavPropertyETTwoPrimMany HTTP/1.1" + CRLF + "Content-Type: application/json;odata=verbose" + CRLF + CRLF + CRLF @@ -390,8 +386,7 @@ public class MockedBatchHandlerTest { + "Content-Transfer-Encoding: binary" + CRLF + "Content-Id: 2" + CRLF + CRLF - + "POST /$1/NavPropertyETTwoPrimMany HTTP/1.1" + CRLF - + "Host: http://localhost:8080/odata" + CRLF + + "POST $1/NavPropertyETTwoPrimMany HTTP/1.1" + CRLF + "Content-Type: application/json;odata=verbose" + CRLF + CRLF + CRLF diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/deserializer/BatchRequestParserTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/deserializer/BatchRequestParserTest.java index 7beda1d4d..7a63874aa 100644 --- a/lib/server-core/src/test/java/org/apache/olingo/server/core/deserializer/BatchRequestParserTest.java +++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/deserializer/BatchRequestParserTest.java @@ -602,7 +602,7 @@ public class BatchRequestParserTest { } @Test - public void testInvalidUri() throws Exception { + public void testAbsoluteUri() throws Exception { final String batch = "" + "--batch_8194-cf13-1f56" + CRLF + MIME_HEADERS @@ -612,7 +612,7 @@ public class BatchRequestParserTest { + CRLF + "--batch_8194-cf13-1f56--"; - parseInvalidBatchBody(batch, BatchDeserializerException.MessageKeys.INVALID_URI); + parseInvalidBatchBody(batch, BatchDeserializerException.MessageKeys.FORBIDDEN_ABSOLUTE_URI); } @Test @@ -627,17 +627,7 @@ public class BatchRequestParserTest { + CRLF + "--batch_8194-cf13-1f56--"; - final List parts = parse(batch); - 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()); + parseInvalidBatchBody(batch, BatchDeserializerException.MessageKeys.INVALID_URI); } @Test @@ -651,23 +641,7 @@ public class BatchRequestParserTest { + CRLF + "--batch_8194-cf13-1f56--"; - parseInvalidBatchBody(batch, MessageKeys.MISSING_MANDATORY_HEADER); - } - - @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); + parseInvalidBatchBody(batch, MessageKeys.INVALID_URI); } @Test diff --git a/lib/server-core/src/test/resources/batchWithPost.batch b/lib/server-core/src/test/resources/batchWithPost.batch index b7038e915..227c3d349 100644 --- a/lib/server-core/src/test/resources/batchWithPost.batch +++ b/lib/server-core/src/test/resources/batchWithPost.batch @@ -2,7 +2,7 @@ Content-Type: application/http 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-Language:en-US,en;q=0.7,en-UK;q=0.9 MaxDataServiceVersion: 2.0