Repository: olingo-odata2 Updated Branches: refs/heads/master e7e44471c -> 86c4ddc42
[OLINGO-436] Fix: Validate request HTTP version Signed-off-by: Christian Amend <[email protected]> Project: http://git-wip-us.apache.org/repos/asf/olingo-odata2/repo Commit: http://git-wip-us.apache.org/repos/asf/olingo-odata2/commit/86c4ddc4 Tree: http://git-wip-us.apache.org/repos/asf/olingo-odata2/tree/86c4ddc4 Diff: http://git-wip-us.apache.org/repos/asf/olingo-odata2/diff/86c4ddc4 Branch: refs/heads/master Commit: 86c4ddc4205aa29d744ec8b3047fae15541a1493 Parents: e7e4447 Author: Christian Holzer <[email protected]> Authored: Tue Oct 14 13:04:58 2014 +0200 Committer: Christian Amend <[email protected]> Committed: Tue Oct 14 13:59:48 2014 +0200 ---------------------------------------------------------------------- .../odata2/api/batch/BatchParserResult.java | 6 + .../odata2/core/batch/v2/BatchParserCommon.java | 103 ++-------- .../batch/v2/BatchRequestTransformator.java | 75 ++------ .../batch/v2/BatchResponseTransformator.java | 34 +--- .../core/batch/v2/BatchTransformatorCommon.java | 188 ++++++++++++++++++- .../core/batch/BatchRequestParserTest.java | 92 +++++++-- .../odata2/core/batch/BatchRequestTest.java | 1 - .../BufferedReaderIncludingLineEndingsTest.java | 13 +- 8 files changed, 322 insertions(+), 190 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/86c4ddc4/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/batch/BatchParserResult.java ---------------------------------------------------------------------- diff --git a/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/batch/BatchParserResult.java b/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/batch/BatchParserResult.java index 1e2054f..842933d 100644 --- a/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/batch/BatchParserResult.java +++ b/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/batch/BatchParserResult.java @@ -18,6 +18,12 @@ ******************************************************************************/ package org.apache.olingo.odata2.api.batch; +/** + * A BatchParserResult + * + * <p> BatchParserResult represents a BatchRequestPart or a BatchResponse part. + * + */ public interface BatchParserResult { } http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/86c4ddc4/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchParserCommon.java ---------------------------------------------------------------------- diff --git a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchParserCommon.java b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchParserCommon.java index cac340e..62f03c2 100644 --- a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchParserCommon.java +++ b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchParserCommon.java @@ -20,8 +20,6 @@ package org.apache.olingo.odata2.core.batch.v2; import java.io.ByteArrayInputStream; import java.io.InputStream; -import java.net.URI; -import java.net.URISyntaxException; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; @@ -35,10 +33,6 @@ import java.util.regex.Pattern; import org.apache.olingo.odata2.api.batch.BatchException; import org.apache.olingo.odata2.api.commons.HttpContentType; import org.apache.olingo.odata2.api.commons.HttpHeaders; -import org.apache.olingo.odata2.api.uri.PathInfo; -import org.apache.olingo.odata2.api.uri.PathSegment; -import org.apache.olingo.odata2.core.ODataPathSegmentImpl; -import org.apache.olingo.odata2.core.PathInfoImpl; import org.apache.olingo.odata2.core.batch.AcceptParser; import org.apache.olingo.odata2.core.batch.v2.BufferedReaderIncludingLineEndings.Line; import org.apache.olingo.odata2.core.commons.Decoder; @@ -58,16 +52,16 @@ public class BatchParserCommon { public static final Pattern PATTERN_HEADER_LINE = Pattern.compile("([a-zA-Z\\-]+):\\s?(.*)\\s*"); public static final Pattern PATTERN_CONTENT_TYPE_APPLICATION_HTTP = Pattern.compile(REG_EX_APPLICATION_HTTP, Pattern.CASE_INSENSITIVE); - private static final Pattern PATTERN_RELATIVE_URI = Pattern.compile("([^/][^?]*)(\\?.*)?"); + public static final Pattern PATTERN_RELATIVE_URI = Pattern.compile("([^/][^?]*)(\\?.*)?"); public static String trimLineListToLength(final List<Line> list, final int length) { - final String message = stringListToString(list); + final String message = lineListToString(list); final int lastIndex = Math.min(length, message.length()); return (lastIndex > 0) ? message.substring(0, lastIndex) : ""; } - public static String stringListToString(final List<Line> list) { + public static String lineListToString(final List<Line> list) { StringBuilder builder = new StringBuilder(); for (Line currentLine : list) { @@ -77,16 +71,16 @@ public class BatchParserCommon { return builder.toString(); } - public static InputStream convertMessageToInputStream(final List<Line> messageList, final int contentLength) + public static InputStream convertLineListToInputStream(final List<Line> messageList, final int contentLength) throws BatchException { final String message = trimLineListToLength(messageList, contentLength); return new ByteArrayInputStream(message.getBytes()); } - public static InputStream convertMessageToInputStream(final List<Line> messageList) + public static InputStream convertLineListToInputStream(final List<Line> messageList) throws BatchException { - final String message = stringListToString(messageList); + final String message = lineListToString(messageList); return new ByteArrayInputStream(message.getBytes()); } @@ -158,14 +152,14 @@ public class BatchParserCommon { } public static Header consumeHeaders(final List<Line> remainingMessage) throws BatchException { - final int lineNumberOfHeader = remainingMessage.size() != 0 ? remainingMessage.get(0).getLineNumber() : 0; - final Header headers = new Header(lineNumberOfHeader); - boolean isHeader = true; + final int headerLineNumber = remainingMessage.size() != 0 ? remainingMessage.get(0).getLineNumber() : 0; + final Header headers = new Header(headerLineNumber); final Iterator<Line> iter = remainingMessage.iterator(); final AcceptParser acceptParser = new AcceptParser(); Line currentLine; int acceptLineNumber = 0; int acceptLanguageLineNumber = 0; + boolean isHeader = true; while (iter.hasNext() && isHeader) { currentLine = iter.next(); @@ -224,6 +218,14 @@ public class BatchParserCommon { } } + private static String trimQuota(String boundary) { + if (boundary.matches("\".*\"")) { + boundary = boundary.replace("\"", ""); + } + + return boundary; + } + public static Map<String, List<String>> parseQueryParameter(final Line httpRequest) { Map<String, List<String>> queryParameter = new HashMap<String, List<String>>(); @@ -254,75 +256,4 @@ public class BatchParserCommon { return queryParameter; } - - public static PathInfo parseRequestUri(final Line httpStatusLine, final PathInfo batchRequestPathInfo, - final String baseUri, final int line) - throws BatchException { - - final String odataPathSegmentsAsString; - final String queryParametersAsString; - - PathInfoImpl pathInfo = new PathInfoImpl(); - pathInfo.setServiceRoot(batchRequestPathInfo.getServiceRoot()); - pathInfo.setPrecedingPathSegment(batchRequestPathInfo.getPrecedingSegments()); - - String[] requestParts = httpStatusLine.toString().split(" "); - if (requestParts.length == 3) { - String uri = requestParts[1]; - Pattern regexRequestUri; - - try { - URI uriObject = new URI(uri); - if (uriObject.isAbsolute()) { - regexRequestUri = Pattern.compile(baseUri + "/([^/][^?]*)(\\?.*)?"); - } else { - regexRequestUri = PATTERN_RELATIVE_URI; - - } - - Matcher uriParts = regexRequestUri.matcher(uri); - - if (uriParts.lookingAt() && uriParts.groupCount() == 2) { - odataPathSegmentsAsString = uriParts.group(1); - queryParametersAsString = uriParts.group(2) != null ? uriParts.group(2) : ""; - - pathInfo.setODataPathSegment(parseODataPathSegments(odataPathSegmentsAsString)); - if (!odataPathSegmentsAsString.startsWith("$")) { - String requestUri = baseUri + "/" + odataPathSegmentsAsString + queryParametersAsString; - pathInfo.setRequestUri(new URI(requestUri)); - } - - } else { - throw new BatchException(BatchException.INVALID_URI.addContent(httpStatusLine.getLineNumber())); - } - - } catch (URISyntaxException e) { - throw new BatchException(BatchException.INVALID_URI.addContent(line), e); - } - } else { - throw new BatchException(BatchException.INVALID_REQUEST_LINE.addContent(httpStatusLine.toString()) - .addContent(line)); - } - - return pathInfo; - } - - public static List<PathSegment> parseODataPathSegments(final String odataPathSegmentsAsString) { - final List<PathSegment> odataPathSegments = new ArrayList<PathSegment>(); - final String[] pathParts = odataPathSegmentsAsString.split("/"); - - for (final String pathSegment : pathParts) { - odataPathSegments.add(new ODataPathSegmentImpl(pathSegment, null)); - } - - return odataPathSegments; - } - - private static String trimQuota(String boundary) { - if (boundary.matches("\".*\"")) { - boundary = boundary.replace("\"", ""); - } - - return boundary; - } } http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/86c4ddc4/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchRequestTransformator.java ---------------------------------------------------------------------- diff --git a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchRequestTransformator.java b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchRequestTransformator.java index 4faac22..66600b5 100644 --- a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchRequestTransformator.java +++ b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchRequestTransformator.java @@ -21,12 +21,9 @@ package org.apache.olingo.odata2.core.batch.v2; import java.io.ByteArrayInputStream; import java.io.InputStream; import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Locale; -import java.util.Set; import org.apache.olingo.odata2.api.batch.BatchException; import org.apache.olingo.odata2.api.batch.BatchParserResult; @@ -37,15 +34,11 @@ import org.apache.olingo.odata2.api.processor.ODataRequest.ODataRequestBuilder; import org.apache.olingo.odata2.api.uri.PathInfo; import org.apache.olingo.odata2.core.batch.BatchHelper; import org.apache.olingo.odata2.core.batch.BatchRequestPartImpl; -import org.apache.olingo.odata2.core.batch.v2.BufferedReaderIncludingLineEndings.Line; +import org.apache.olingo.odata2.core.batch.v2.BatchTransformatorCommon.HttpRequestStatusLine; import org.apache.olingo.odata2.core.batch.v2.Header.HeaderField; public class BatchRequestTransformator implements BatchTransformator { - 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", - "PUT", "DELETE", "MERGE", "PATCH" })); - @Override public List<BatchParserResult> transform(final BatchBodyPart bodyPart, final PathInfo pathInfo, final String baseUri) throws BatchException { @@ -89,19 +82,21 @@ public class BatchRequestTransformator implements BatchTransformator { private ODataRequest createRequest(final BatchQueryOperation operation, final Header headers, final PathInfo pathInfo, final String baseUri, final boolean isChangeSet) throws BatchException { - final int httpLineNumber = operation.getHttpStatusLine().getLineNumber(); - ODataHttpMethod httpMethod = getHttpMethod(operation.getHttpStatusLine()); - validateHttpMethod(httpMethod, isChangeSet, httpLineNumber); - validateBody(httpMethod, operation, httpLineNumber); - InputStream bodyStrean = getBodyStream(operation, headers, httpMethod); + final HttpRequestStatusLine statusLine = new HttpRequestStatusLine( operation.getHttpStatusLine(), + baseUri, + pathInfo); + statusLine.validateHttpMethod(isChangeSet); + + validateBody(statusLine, operation); + InputStream bodyStrean = getBodyStream(operation, headers, statusLine); - ODataRequestBuilder requestBuilder = ODataRequest.method(httpMethod) + ODataRequestBuilder requestBuilder = ODataRequest.method(statusLine.getMethod()) .acceptableLanguages(getAcceptLanguageHeaders(headers)) .acceptHeaders(headers.getHeaders(HttpHeaders.ACCEPT)) .allQueryParameters(BatchParserCommon.parseQueryParameter(operation.getHttpStatusLine())) .body(bodyStrean) .requestHeaders(headers.toMultiMap()) - .pathInfo(BatchParserCommon.parseRequestUri(operation.getHttpStatusLine(), pathInfo, baseUri, 0)); + .pathInfo(statusLine.getPathInfo()); final String contentType = headers.getHeader(HttpHeaders.CONTENT_TYPE); if (contentType != null) { @@ -111,30 +106,32 @@ public class BatchRequestTransformator implements BatchTransformator { return requestBuilder.build(); } - private void validateBody(final ODataHttpMethod httpStatusLine, final BatchQueryOperation operation, final int line) + private void validateBody(final HttpRequestStatusLine httpStatusLine, final BatchQueryOperation operation) throws BatchException { - if (HTTP_BATCH_METHODS.contains(httpStatusLine.toString()) && isUnvalidGetRequestBody(operation)) { - throw new BatchException(BatchException.INVALID_REQUEST_LINE.addContent(httpStatusLine).addContent(line)); + if (httpStatusLine.getMethod().equals(ODataHttpMethod.GET) && isUnvalidGetRequestBody(operation)) { + throw new BatchException(BatchException.INVALID_REQUEST_LINE + .addContent(httpStatusLine.getMethod()) + .addContent(httpStatusLine.getLineNumber())); } } private boolean isUnvalidGetRequestBody(final BatchQueryOperation operation) { return (operation.getBody().size() > 1) - || (operation.getBody().size() == 1 && !operation.getBody().get(0).toString().trim().equals("")); + || (operation.getBody().size() == 1 && !"".equals(operation.getBody().get(0).toString().trim())); } private InputStream getBodyStream(final BatchQueryOperation operation, final Header headers, - final ODataHttpMethod httpMethod) throws BatchException { + final HttpRequestStatusLine httpStatusLine) throws BatchException { - if (HTTP_BATCH_METHODS.contains(httpMethod.toString())) { + if (httpStatusLine.getMethod().equals(ODataHttpMethod.GET)) { return new ByteArrayInputStream(new byte[0]); } else { int contentLength = BatchTransformatorCommon.getContentLength(headers); if (contentLength == -1) { - return BatchParserCommon.convertMessageToInputStream(operation.getBody()); + return BatchParserCommon.convertLineListToInputStream(operation.getBody()); } else { - return BatchParserCommon.convertMessageToInputStream(operation.getBody(), contentLength); + return BatchParserCommon.convertLineListToInputStream(operation.getBody(), contentLength); } } } @@ -157,19 +154,6 @@ public class BatchRequestTransformator implements BatchTransformator { return headers; } - private void validateHttpMethod(final ODataHttpMethod httpMethod, final boolean isChangeSet, final int line) - throws BatchException { - Set<String> validMethods = (isChangeSet) ? HTTP_CHANGE_SET_METHODS : HTTP_BATCH_METHODS; - - if (!validMethods.contains(httpMethod.toString())) { - if (isChangeSet) { - throw new BatchException(BatchException.INVALID_CHANGESET_METHOD.addContent(line)); - } else { - throw new BatchException(BatchException.INVALID_QUERY_OPERATION_METHOD.addContent(line)); - } - } - } - private List<Locale> getAcceptLanguageHeaders(final Header headers) { final List<String> acceptLanguageValues = headers.getHeaders(HttpHeaders.ACCEPT_LANGUAGE); List<Locale> acceptLanguages = new ArrayList<Locale>(); @@ -188,23 +172,4 @@ public class BatchRequestTransformator implements BatchTransformator { return acceptLanguages; } - private ODataHttpMethod getHttpMethod(final Line httpRequest) throws BatchException { - ODataHttpMethod result = null; - - String[] parts = httpRequest.toString().split(" "); - - if (parts.length == 3) { - try { - result = ODataHttpMethod.valueOf(parts[0]); - } catch (IllegalArgumentException e) { - throw new BatchException(BatchException.MISSING_METHOD.addContent(httpRequest.getLineNumber()), e); - } - } else { - throw new BatchException(BatchException.INVALID_REQUEST_LINE.addContent(httpRequest.toString()).addContent( - httpRequest.getLineNumber())); - } - - return result; - } - } http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/86c4ddc4/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchResponseTransformator.java ---------------------------------------------------------------------- diff --git a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchResponseTransformator.java b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchResponseTransformator.java index e800673..5e4198c 100644 --- a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchResponseTransformator.java +++ b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchResponseTransformator.java @@ -20,8 +20,6 @@ package org.apache.olingo.odata2.core.batch.v2; import java.util.ArrayList; import java.util.List; -import java.util.regex.Matcher; -import java.util.regex.Pattern; import org.apache.olingo.odata2.api.batch.BatchException; import org.apache.olingo.odata2.api.batch.BatchParserResult; @@ -29,12 +27,10 @@ import org.apache.olingo.odata2.api.client.batch.BatchSingleResponse; import org.apache.olingo.odata2.api.uri.PathInfo; import org.apache.olingo.odata2.core.batch.BatchHelper; import org.apache.olingo.odata2.core.batch.BatchSingleResponseImpl; -import org.apache.olingo.odata2.core.batch.v2.BufferedReaderIncludingLineEndings.Line; +import org.apache.olingo.odata2.core.batch.v2.BatchTransformatorCommon.HttpResponsetStatusLine; public class BatchResponseTransformator implements BatchTransformator { - private static final String REG_EX_STATUS_LINE = "(?:HTTP/[0-9]\\.[0-9])\\s([0-9]{3})\\s([\\S ]+)\\s*"; - public BatchResponseTransformator() {} @Override @@ -81,46 +77,26 @@ public class BatchResponseTransformator implements BatchTransformator { private BatchSingleResponse transformQueryOperation(final BatchQueryOperation operation, final String contentId) throws BatchException { - final Matcher statusMatcher = prepareStatusLineMatcher(operation.getHttpStatusLine()); + final HttpResponsetStatusLine statusLine = new HttpResponsetStatusLine(operation.getHttpStatusLine()); BatchSingleResponseImpl response = new BatchSingleResponseImpl(); response.setContentId(contentId); response.setHeaders(operation.getHeaders().toSingleMap()); - response.setStatusCode(getStatusCode(statusMatcher)); - response.setStatusInfo(getStatusInfo(statusMatcher)); + response.setStatusCode(statusLine.getStatusCode()); + response.setStatusInfo(statusLine.getStatusInfo()); response.setBody(getBody(operation)); return response; } - private Matcher prepareStatusLineMatcher(final Line httpStatusLine) throws BatchException { - final Pattern regexPattern = Pattern.compile(REG_EX_STATUS_LINE); - final Matcher matcher = regexPattern.matcher(httpStatusLine.toString()); - - if (matcher.find()) { - return matcher; - } else { - throw new BatchException(BatchException.INVALID_STATUS_LINE.addContent(httpStatusLine.toString()) - .addContent(httpStatusLine.getLineNumber())); - } - } - private String getBody(final BatchQueryOperation operation) throws BatchException { int contentLength = BatchTransformatorCommon.getContentLength(operation.getHeaders()); if (contentLength == -1) { - return BatchParserCommon.stringListToString(operation.getBody()); + return BatchParserCommon.lineListToString(operation.getBody()); } else { return BatchParserCommon.trimLineListToLength(operation.getBody(), contentLength); } } - private String getStatusCode(final Matcher matcher) throws BatchException { - return matcher.group(1); - } - - private String getStatusInfo(final Matcher matcher) throws BatchException { - return matcher.group(2); - } - } http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/86c4ddc4/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchTransformatorCommon.java ---------------------------------------------------------------------- diff --git a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchTransformatorCommon.java b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchTransformatorCommon.java index 521b4e1..c07c06f 100644 --- a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchTransformatorCommon.java +++ b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchTransformatorCommon.java @@ -18,16 +18,29 @@ ******************************************************************************/ package org.apache.olingo.odata2.core.batch.v2; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; +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.odata2.api.batch.BatchException; import org.apache.olingo.odata2.api.commons.HttpContentType; import org.apache.olingo.odata2.api.commons.HttpHeaders; +import org.apache.olingo.odata2.api.commons.ODataHttpMethod; +import org.apache.olingo.odata2.api.uri.PathInfo; +import org.apache.olingo.odata2.api.uri.PathSegment; +import org.apache.olingo.odata2.core.ODataPathSegmentImpl; +import org.apache.olingo.odata2.core.PathInfoImpl; import org.apache.olingo.odata2.core.batch.BatchHelper; +import org.apache.olingo.odata2.core.batch.v2.BufferedReaderIncludingLineEndings.Line; import org.apache.olingo.odata2.core.batch.v2.Header.HeaderField; public class BatchTransformatorCommon { - public static void validateContentType(final Header headers) throws BatchException { List<String> contentTypes = headers.getHeaders(HttpHeaders.CONTENT_TYPE); @@ -87,4 +100,177 @@ public class BatchTransformatorCommon { return -1; } + + public static class HttpResponsetStatusLine { + private static final String REG_EX_STATUS_LINE = "(?:HTTP/[0-9]\\.[0-9])\\s([0-9]{3})\\s([\\S ]+)\\s*"; + private Line httpStatusLine; + private String statusCode; + private String statusInfo; + + public HttpResponsetStatusLine(final Line httpStatusLine) throws BatchException { + this.httpStatusLine = httpStatusLine; + parse(); + } + + private void parse() throws BatchException { + final Pattern regexPattern = Pattern.compile(REG_EX_STATUS_LINE); + final Matcher matcher = regexPattern.matcher(httpStatusLine.toString()); + + if (matcher.find()) { + statusCode = matcher.group(1); + statusInfo = matcher.group(2); + } else { + throw new BatchException(BatchException.INVALID_STATUS_LINE.addContent(httpStatusLine.toString()) + .addContent(httpStatusLine.getLineNumber())); + } + } + + public String getStatusCode() { + return statusCode; + } + + public String getStatusInfo() { + return statusInfo; + } + } + + public static class HttpRequestStatusLine { + 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", + "PUT", "DELETE", "MERGE", "PATCH" })); + private static final String HTTP_VERSION = "HTTP/1.1"; + + final private Line statusLine; + final String requestBaseUri; + final PathInfo batchRequestPathInfo; + + private ODataHttpMethod method; + private PathInfo pathInfo; + private String httpVersion; + + public HttpRequestStatusLine(final Line httpStatusLine, final String baseUri, final PathInfo pathInfo) + throws BatchException { + statusLine = httpStatusLine; + requestBaseUri = baseUri; + batchRequestPathInfo = pathInfo; + + parse(); + } + + private void parse() throws BatchException { + final String[] parts = statusLine.toString().split(" "); + + if (parts.length == 3) { + try { + method = parseMethod(parts[0]); + pathInfo = parseUri(parts[1]); + httpVersion = parseHttpVersion(parts[2]); + } catch (IllegalArgumentException e) { + throw new BatchException(BatchException.MISSING_METHOD.addContent(statusLine.getLineNumber()), e); + } + } else { + throw new BatchException(BatchException.INVALID_REQUEST_LINE.addContent(statusLine.toString()) + .addContent(statusLine.getLineNumber())); + } + } + + private ODataHttpMethod parseMethod(final String method) throws BatchException { + try { + return ODataHttpMethod.valueOf(method.trim()); + } catch (IllegalArgumentException e) { + throw new BatchException(BatchException.MISSING_METHOD.addContent(statusLine.getLineNumber()), e); + } + } + + private PathInfo parseUri(final String uri) + throws BatchException { + final PathInfoImpl pathInfo = new PathInfoImpl(); + final String odataPathSegmentsAsString; + final String queryParametersAsString; + Pattern regexRequestUri; + + pathInfo.setServiceRoot(batchRequestPathInfo.getServiceRoot()); + pathInfo.setPrecedingPathSegment(batchRequestPathInfo.getPrecedingSegments()); + + try { + URI uriObject = new URI(uri); + if (uriObject.isAbsolute()) { + regexRequestUri = Pattern.compile(requestBaseUri + "/([^/][^?]*)(\\?.*)?"); + } else { + regexRequestUri = BatchParserCommon.PATTERN_RELATIVE_URI; + + } + + Matcher uriParts = regexRequestUri.matcher(uri); + + if (uriParts.lookingAt() && uriParts.groupCount() == 2) { + odataPathSegmentsAsString = uriParts.group(1); + queryParametersAsString = uriParts.group(2) != null ? uriParts.group(2) : ""; + + pathInfo.setODataPathSegment(parseODataPathSegments(odataPathSegmentsAsString)); + if (!odataPathSegmentsAsString.startsWith("$")) { + String requestUri = requestBaseUri + "/" + odataPathSegmentsAsString + queryParametersAsString; + pathInfo.setRequestUri(new URI(requestUri)); + } + + } else { + throw new BatchException(BatchException.INVALID_URI.addContent(statusLine.getLineNumber())); + } + } catch (URISyntaxException e) { + throw new BatchException(BatchException.INVALID_URI.addContent(statusLine.getLineNumber()), e); + } + + return pathInfo; + } + + private List<PathSegment> parseODataPathSegments(final String odataPathSegmentsAsString) { + final List<PathSegment> odataPathSegments = new ArrayList<PathSegment>(); + final String[] pathParts = odataPathSegmentsAsString.split("/"); + + for (final String pathSegment : pathParts) { + odataPathSegments.add(new ODataPathSegmentImpl(pathSegment, null)); + } + + return odataPathSegments; + } + + private String parseHttpVersion(final String httpVersion) throws BatchException { + if (!HTTP_VERSION.equals(httpVersion.trim())) { + throw new BatchException(BatchException.INVALID_REQUEST_LINE + .addContent(statusLine.toString()) + .addContent(statusLine.getLineNumber())); + } else { + return HTTP_VERSION; + } + } + + public void validateHttpMethod(boolean isChangeSet) throws BatchException { + Set<String> validMethods = (isChangeSet) ? HTTP_CHANGE_SET_METHODS : HTTP_BATCH_METHODS; + + if (!validMethods.contains(getMethod().toString())) { + if (isChangeSet) { + throw new BatchException(BatchException.INVALID_CHANGESET_METHOD.addContent(statusLine.getLineNumber())); + } else { + throw new BatchException(BatchException.INVALID_QUERY_OPERATION_METHOD + .addContent(statusLine.getLineNumber())); + } + } + } + + public ODataHttpMethod getMethod() { + return method; + } + + public PathInfo getPathInfo() { + return pathInfo; + } + + public String getHttpVersion() { + return httpVersion; + } + + public int getLineNumber() { + return statusLine.getLineNumber(); + } + } } http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/86c4ddc4/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchRequestParserTest.java ---------------------------------------------------------------------- diff --git a/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchRequestParserTest.java b/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchRequestParserTest.java index 52550fb..1a374a5 100644 --- a/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchRequestParserTest.java +++ b/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchRequestParserTest.java @@ -41,7 +41,6 @@ import org.apache.olingo.odata2.core.PathInfoImpl; import org.apache.olingo.odata2.core.batch.v2.BatchParser; import org.apache.olingo.odata2.testutil.helper.StringHelper; import org.junit.BeforeClass; -import org.junit.Ignore; import org.junit.Test; public class BatchRequestParserTest { @@ -119,7 +118,7 @@ public class BatchRequestParserTest { } } } - + @Test public void testImageInContent() throws IOException, BatchException, URISyntaxException { String fileName = "/batchWithContent.batch"; @@ -271,6 +270,51 @@ public class BatchRequestParserTest { parseInvalidBatchBody(batch); } + @Test(expected=BatchException.class) + public void testMissingHttpVersion() throws BatchException { + String batch = "" + + "--batch_8194-cf13-1f56" + CRLF + + "Content-Type: application/http" + CRLF + + "Content-Transfer-Encoding:binary" + CRLF + + CRLF + + "GET Employees?$format=json" + CRLF + + "Host: localhost:8080" + CRLF + + CRLF + + "--batch_8194-cf13-1f56--"; + + parseInvalidBatchBody(batch); + } + + @Test(expected=BatchException.class) + public void testMissingHttpVersion2() throws BatchException { + String batch = "" + + "--batch_8194-cf13-1f56" + CRLF + + "Content-Type: application/http" + CRLF + + "Content-Transfer-Encoding:binary" + CRLF + + CRLF + + "GET Employees?$format=json " + CRLF + + "Host: localhost:8080" + CRLF + + CRLF + + "--batch_8194-cf13-1f56--"; + + parseInvalidBatchBody(batch); + } + + @Test(expected=BatchException.class) + public void testMissingHttpVersion3() throws BatchException { + String batch = "" + + "--batch_8194-cf13-1f56" + CRLF + + "Content-Type: application/http" + CRLF + + "Content-Transfer-Encoding:binary" + CRLF + + CRLF + + "GET Employees?$format=json SMTP:3.1" + CRLF + + "Host: localhost:8080" + CRLF + + CRLF + + "--batch_8194-cf13-1f56--"; + + parseInvalidBatchBody(batch); + } + @Test(expected = BatchException.class) public void testBoundaryWithoutHyphen() throws BatchException { String batch = "--batch_8194-cf13-1f56" + CRLF @@ -347,19 +391,6 @@ public class BatchRequestParserTest { } @Test(expected = BatchException.class) - @Ignore("What should here throw an exception") - public void testMimeHeaderContentId() throws BatchException { - String batch = "--batch_8194-cf13-1f56" + CRLF - + MIME_HEADERS - + "Content-ID: 1" + CRLF - + CRLF - + "GET Employees('1')/EmployeeName HTTP/1.1" + CRLF - + CRLF - + "--batch_8194-cf13-1f56--"; - parseInvalidBatchBody(batch); - } - - @Test(expected = BatchException.class) public void testInvalidMethodForBatch() throws BatchException { String batch = "--batch_8194-cf13-1f56" + CRLF + MIME_HEADERS @@ -413,7 +444,7 @@ public class BatchRequestParserTest { parseInvalidBatchBody(batch); } - @Test(expected = BatchException.class) + @Test(expected=BatchException.class) public void testInvalidChangeSetBoundary() throws BatchException { String batch = "--batch_8194-cf13-1f56" + CRLF + "Content-Type: multipart/mixed;boundary=changeset_f980-1cb6-94dd" + CRLF @@ -425,10 +456,37 @@ public class BatchRequestParserTest { + "Content-Type: application/json;odata=verbose" + CRLF + "MaxDataServiceVersion: 2.0" + CRLF + CRLF + + "--changeset_f980-1cb6-94dd--" + CRLF + + CRLF + "--batch_8194-cf13-1f56--"; parseInvalidBatchBody(batch); } - + + @Test(expected=BatchException.class) + public void testNestedChangeset() throws BatchException { + String batch = "--batch_8194-cf13-1f56" + CRLF + + "Content-Type: multipart/mixed;boundary=changeset_f980-1cb6-94dd" + CRLF + + CRLF + + "--changeset_f980-1cb6-94dd" + CRLF + + MIME_HEADERS + + CRLF + + "Content-Type: multipart/mixed;boundary=changeset_f980-1cb6-94dd2" + CRLF + + CRLF + + "--changeset_f980-1cb6-94dd2" + CRLF + + MIME_HEADERS + + CRLF + + "POST Employees('2') HTTP/1.1" + CRLF + + "Content-Type: application/json;odata=verbose" + CRLF + + "MaxDataServiceVersion: 2.0" + CRLF + + CRLF + + "--changeset_f980-1cb6-94dd--" + CRLF + + CRLF + + "--changeset_f980-1cb6-94dd--" + CRLF + + CRLF + + "--batch_8194-cf13-1f56--"; + parse(batch); + } + @Test(expected = BatchException.class) public void testMissingContentTransferEncoding() throws BatchException { String batch = "--batch_8194-cf13-1f56" + CRLF http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/86c4ddc4/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchRequestTest.java ---------------------------------------------------------------------- diff --git a/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchRequestTest.java b/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchRequestTest.java index bcf13e4..116bfd7 100644 --- a/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchRequestTest.java +++ b/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchRequestTest.java @@ -132,7 +132,6 @@ public class BatchRequestTest { } @Test - // TODO /* * --batch_123 * Content-Type: application/http http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/86c4ddc4/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BufferedReaderIncludingLineEndingsTest.java ---------------------------------------------------------------------- diff --git a/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BufferedReaderIncludingLineEndingsTest.java b/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BufferedReaderIncludingLineEndingsTest.java index 1161530..69b546f 100644 --- a/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BufferedReaderIncludingLineEndingsTest.java +++ b/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BufferedReaderIncludingLineEndingsTest.java @@ -378,7 +378,18 @@ public class BufferedReaderIncludingLineEndingsTest { assertEquals(null, reader.readLine()); assertEquals(-1, reader.read()); } - + + @Test + public void testLineEqualsAndHashCode() { + Line l1 = new Line("The first line", 1); + Line l2 = new Line("The first line", 1); + Line l3 = new Line("The second line", 2); + + assertEquals(l1, l2); + assertFalse(l1.equals(l3)); + assertTrue(l1.hashCode() != l3.hashCode()); + } + @Test(expected = IllegalArgumentException.class) public void testSkipNegative() throws IOException { BufferedReaderIncludingLineEndings reader = create("123");
