Code Review - Bug fix and refactoring 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/1f90b733 Tree: http://git-wip-us.apache.org/repos/asf/olingo-odata2/tree/1f90b733 Diff: http://git-wip-us.apache.org/repos/asf/olingo-odata2/diff/1f90b733 Branch: refs/heads/master Commit: 1f90b733a25a41c43f93ceb0f78369e6c27ef753 Parents: ffb21db Author: Christian Holzer <[email protected]> Authored: Thu Oct 2 19:12:38 2014 +0200 Committer: Christian Amend <[email protected]> Committed: Mon Oct 6 13:54:37 2014 +0200 ---------------------------------------------------------------------- .../olingo/odata2/core/batch/AcceptParser.java | 64 +++++-- .../odata2/core/batch/v2/BatchBodyPart.java | 27 +-- .../odata2/core/batch/v2/BatchChangeSet.java | 55 ------ .../core/batch/v2/BatchChangeSetPart.java | 55 ++++++ .../odata2/core/batch/v2/BatchParser.java | 2 +- .../odata2/core/batch/v2/BatchParserCommon.java | 122 +++++++------ .../core/batch/v2/BatchQueryOperation.java | 10 +- .../batch/v2/BatchRequestTransformator.java | 16 +- .../batch/v2/BatchResponseTransformator.java | 13 +- .../core/batch/v2/BatchTransformatorCommon.java | 24 +-- .../odata2/core/batch/AcceptParserTest.java | 77 +++++--- .../core/batch/BatchParserCommonTest.java | 182 +++++++++++++++---- .../core/batch/BatchRequestParserTest.java | 124 +++++++++---- .../batch/BatchTransformatorCommonTest.java | 12 +- 14 files changed, 516 insertions(+), 267 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/1f90b733/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/AcceptParser.java ---------------------------------------------------------------------- diff --git a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/AcceptParser.java b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/AcceptParser.java index 946fccf..48bfb1b 100644 --- a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/AcceptParser.java +++ b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/AcceptParser.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 @@ -20,6 +20,7 @@ package org.apache.olingo.odata2.core.batch; import java.util.ArrayList; import java.util.Comparator; +import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Scanner; @@ -30,10 +31,11 @@ import java.util.regex.Pattern; import org.apache.olingo.odata2.api.batch.BatchException; /** - * + * */ public class AcceptParser { + private static final String COMMA = ","; private static final String BAD_REQUEST = "400"; private static final String ALL = "*"; private static final String REG_EX_QUALITY_FACTOR = "q=((?:1\\.0{0,3})|(?:0\\.[0-9]{0,2}[1-9]))"; @@ -48,10 +50,15 @@ public class AcceptParser { private static final double QUALITY_PARAM_FACTOR = 0.001; - public static List<String> parseAcceptHeaders(final String headerValue) throws BatchException { - TreeSet<Accept> acceptTree = getAcceptTree(); - List<String> acceptHeaders = new ArrayList<String>(); - Scanner acceptHeaderScanner = new Scanner(headerValue); + private List<String> acceptHeaderValues = new ArrayList<String>(); + private List<String> acceptLanguageHeaderValues = new ArrayList<String>(); + + public List<String> parseAcceptHeaders() throws BatchException { + final String headerValue = concatenateHeaderLines(acceptHeaderValues); + final TreeSet<Accept> acceptTree = getAcceptTree(); + final List<String> acceptHeaders = new ArrayList<String>(); + final Scanner acceptHeaderScanner = new Scanner(headerValue); + acceptHeaderScanner.useDelimiter(",\\s?"); while (acceptHeaderScanner.hasNext()) { if (acceptHeaderScanner.hasNext(REG_EX_ACCEPT_WITH_Q_FACTOR)) { @@ -75,18 +82,21 @@ public class AcceptParser { } } for (Accept accept : acceptTree) { - acceptHeaders.add(accept.getValue()); + if (!acceptHeaders.contains(accept.getValue())) { + acceptHeaders.add(accept.getValue()); + } } acceptHeaderScanner.close(); return acceptHeaders; } - private static double getQualityFactor(final String acceptHeaderValue, double qualityFactor) { + private double getQualityFactor(final String acceptHeaderValue, double qualityFactor) { int paramNumber = 0; double typeFactor = 0.0; double subtypeFactor = 0.0; String[] mediaRange = acceptHeaderValue.split("(?=[^;]+);"); String[] mediaTypes = mediaRange[0].split("/"); + if (mediaTypes.length == 2) { String type = mediaTypes[0]; String subtype = mediaTypes[1]; @@ -101,13 +111,15 @@ public class AcceptParser { String[] parameters = mediaRange[1].split(";\\s?"); paramNumber = parameters.length; } + qualityFactor = qualityFactor + paramNumber * QUALITY_PARAM_FACTOR + typeFactor + subtypeFactor; return qualityFactor; } - public static List<String> parseAcceptableLanguages(final String headerValue) throws BatchException { - List<String> acceptLanguages = new LinkedList<String>(); - TreeSet<Accept> acceptTree = getAcceptTree(); + public List<String> parseAcceptableLanguages() throws BatchException { + final String headerValue = concatenateHeaderLines(acceptLanguageHeaderValues); + final List<String> acceptLanguages = new LinkedList<String>(); + final TreeSet<Accept> acceptTree = getAcceptTree(); Scanner acceptLanguageScanner = new Scanner(headerValue); acceptLanguageScanner.useDelimiter(",\\s?"); @@ -132,13 +144,37 @@ public class AcceptParser { } } for (Accept accept : acceptTree) { - acceptLanguages.add(accept.getValue()); + if (!acceptLanguages.contains(accept.getValue())) { + acceptLanguages.add(accept.getValue()); + } } acceptLanguageScanner.close(); return acceptLanguages; } - private static TreeSet<Accept> getAcceptTree() { + private String concatenateHeaderLines(final List<String> headerValues) { + final StringBuilder builder = new StringBuilder(); + final Iterator<String> iter = headerValues.iterator(); + + while (iter.hasNext()) { + builder.append(iter.next()); + if (iter.hasNext()) { + builder.append(COMMA); + } + } + + return builder.toString(); + } + + public void addAcceptHeaderValue(final String headerValue) { + acceptHeaderValues.add(headerValue); + } + + public void addAcceptLanguageHeaderValue(final String headerValue) { + acceptLanguageHeaderValues.add(headerValue); + } + + private TreeSet<Accept> getAcceptTree() { TreeSet<Accept> treeSet = new TreeSet<Accept>(new Comparator<Accept>() { @Override public int compare(final Accept o1, final Accept o2) { http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/1f90b733/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchBodyPart.java ---------------------------------------------------------------------- diff --git a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchBodyPart.java b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchBodyPart.java index e355f84..4edcf45 100644 --- a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchBodyPart.java +++ b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchBodyPart.java @@ -24,18 +24,16 @@ import java.util.Locale; import java.util.Map; 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.core.batch.v2.BatchParserCommon.HeaderField; -import org.apache.olingo.odata2.core.exception.ODataRuntimeException; public class BatchBodyPart implements BatchPart { - final private Map<String, HeaderField> headers; final private String boundary; - final private boolean isChangeSet; final private boolean isStrict; - final private List<String> body; - private boolean isParsed = false; + final List<String> remainingMessage = new LinkedList<String>(); + + private Map<String, HeaderField> headers; + private boolean isChangeSet; private List<BatchQueryOperation> requests; public BatchBodyPart(final List<String> bodyPartMessage, final String boundary, final boolean isStrict) @@ -43,19 +41,14 @@ public class BatchBodyPart implements BatchPart { this.boundary = boundary; this.isStrict = isStrict; - List<String> remainingMessage = new LinkedList<String>(); remainingMessage.addAll(bodyPartMessage); + } + public BatchBodyPart parse() throws BatchException { headers = BatchParserCommon.consumeHeaders(remainingMessage); BatchParserCommon.consumeBlankLine(remainingMessage, isStrict); isChangeSet = isChangeSet(headers); - body = remainingMessage; - } - - public BatchBodyPart parse(final int contentLength) throws BatchException { - List<String> remainingMessage = BatchParserCommon.trimStringListToLength(body, contentLength); requests = consumeRequest(remainingMessage); - isParsed = true; return this; } @@ -78,7 +71,7 @@ public class BatchBodyPart implements BatchPart { } private boolean isContentTypeMultiPartMixed(final String contentType) { - return contentType.contains(HttpContentType.MULTIPART_MIXED); + return BatchParserCommon.PATTERN_MULTIPART_BOUNDARY.matcher(contentType).matches(); } private List<BatchQueryOperation> consumeRequest(final List<String> remainingMessage) throws BatchException { @@ -95,7 +88,7 @@ public class BatchBodyPart implements BatchPart { final List<BatchQueryOperation> requestList = new LinkedList<BatchQueryOperation>(); for (List<String> changeRequest : changeRequests) { - requestList.add(new BatchChangeSet(changeRequest, isStrict).parse()); + requestList.add(new BatchChangeSetPart(changeRequest, isStrict).parse()); } return requestList; @@ -146,10 +139,6 @@ public class BatchBodyPart implements BatchPart { } public List<BatchQueryOperation> getRequests() { - if (!isParsed) { - throw new ODataRuntimeException("Batch part must be parsed first"); - } - return requests; } } http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/1f90b733/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchChangeSet.java ---------------------------------------------------------------------- diff --git a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchChangeSet.java b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchChangeSet.java deleted file mode 100644 index 5331ff8..0000000 --- a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchChangeSet.java +++ /dev/null @@ -1,55 +0,0 @@ -/******************************************************************************* - * 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.odata2.core.batch.v2; - -import java.util.List; - -import org.apache.olingo.odata2.api.batch.BatchException; - -public class BatchChangeSet extends BatchQueryOperation { - private BatchQueryOperation request; - - public BatchChangeSet(final List<String> message, final boolean isStrict) throws BatchException { - super(message, isStrict); - } - - @Override - public BatchChangeSet parse() throws BatchException { - headers = BatchParserCommon.consumeHeaders(message); - BatchParserCommon.consumeBlankLine(message, isStrict); - - request = new BatchQueryOperation(message, isStrict).parse(); - - return this; - } - - public BatchQueryOperation getRequest() { - return request; - } - - @Override - public List<String> getBody() { - return request.getBody(); - } - - @Override - public String getHttpMethod() { - return request.getHttpMethod(); - } -} http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/1f90b733/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchChangeSetPart.java ---------------------------------------------------------------------- diff --git a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchChangeSetPart.java b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchChangeSetPart.java new file mode 100644 index 0000000..746c368 --- /dev/null +++ b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchChangeSetPart.java @@ -0,0 +1,55 @@ +/******************************************************************************* + * 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.odata2.core.batch.v2; + +import java.util.List; + +import org.apache.olingo.odata2.api.batch.BatchException; + +public class BatchChangeSetPart extends BatchQueryOperation { + private BatchQueryOperation request; + + public BatchChangeSetPart(final List<String> message, final boolean isStrict) throws BatchException { + super(message, isStrict); + } + + @Override + public BatchChangeSetPart parse() throws BatchException { + headers = BatchParserCommon.consumeHeaders(message); + BatchParserCommon.consumeBlankLine(message, isStrict); + + request = new BatchQueryOperation(message, isStrict).parse(); + + return this; + } + + public BatchQueryOperation getRequest() { + return request; + } + + @Override + public List<String> getBody() { + return request.getBody(); + } + + @Override + public String getHttpStatusLine() { + return request.getHttpStatusLine(); + } +} http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/1f90b733/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchParser.java ---------------------------------------------------------------------- diff --git a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchParser.java b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchParser.java index b64453b..6fb7dbd 100644 --- a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchParser.java +++ b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchParser.java @@ -83,7 +83,7 @@ public class BatchParser { final List<List<String>> bodyPartStrings = splitBodyParts(in, boundary); for (List<String> bodyPartString : bodyPartStrings) { - BatchBodyPart bodyPart = new BatchBodyPart(bodyPartString, boundary, isStrict); + BatchBodyPart bodyPart = new BatchBodyPart(bodyPartString, boundary, isStrict).parse(); resultList.addAll(transformator.transform(bodyPart, batchRequestPathInfo, baseUri)); } http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/1f90b733/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 51314dd..8b7f62a 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 @@ -44,32 +44,23 @@ import org.apache.olingo.odata2.core.batch.AcceptParser; import org.apache.olingo.odata2.core.commons.Decoder; public class BatchParserCommon { - private static final String BOUNDARY_IDENTIFIER = "boundary="; private static final String REG_EX_BOUNDARY = "([a-zA-Z0-9_\\-\\.'\\+]{1,70})|\"([a-zA-Z0-9_\\-\\.'\\+\\s\\" + "(\\),/:=\\?]{1,69}[a-zA-Z0-9_\\-\\.'\\+\\(\\),/:=\\?])\""; // See RFC 2046 - private static final Pattern REG_EX_HEADER = Pattern.compile("([a-zA-Z\\-]+):\\s?(.*)\\s*"); + private static final String REX_EX_MULTIPART_BOUNDARY = "multipart/mixed;\\s*boundary=(.+)"; + private static final String REG_EX_APPLICATION_HTTP = "application/http"; + public static final Pattern PATTERN_MULTIPART_BOUNDARY = Pattern.compile(REX_EX_MULTIPART_BOUNDARY, + Pattern.CASE_INSENSITIVE); + 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); - public static List<String> trimStringListToLength(final List<String> list, final int length) { - final Iterator<String> iter = list.iterator(); - final List<String> result = new ArrayList<String>(); - boolean isEndReached = false; - int currentLength = 0; - - while (!isEndReached && iter.hasNext()) { - String currentLine = iter.next(); - - if (currentLength + currentLine.length() <= length) { - result.add(currentLine); - currentLength += currentLine.length(); - } else { - result.add(currentLine.substring(0, length - currentLength)); - isEndReached = true; - } - } + public static String trimStringListToStringLength(final List<String> list, final int length) { + final String message = stringListToString(list); + final int lastIndex = Math.min(length, message.length()); - return result; + return (lastIndex > 0) ? message.substring(0, lastIndex) : ""; } public static String stringListToString(final List<String> list) { @@ -82,13 +73,21 @@ public class BatchParserCommon { return builder.toString(); } - public static InputStream convertMessageToInputStream(final List<String> message, final int contentLength) + public static InputStream convertMessageToInputStream(final List<String> messageList, final int contentLength) throws BatchException { - List<String> shortenedMessage = BatchParserCommon.trimStringListToLength(message, contentLength); + final String message = trimStringListToStringLength(messageList, contentLength); - return new ByteArrayInputStream(BatchParserCommon.stringListToString(shortenedMessage).getBytes()); + return new ByteArrayInputStream(message.getBytes()); } + public static InputStream convertMessageToInputStream(final List<String> messageList) + throws BatchException { + final String message = stringListToString(messageList); + + return new ByteArrayInputStream(message.getBytes()); + } + + // TODO Splitten von InputStream, sodass nur eine Iteration erfolgen muss static List<List<String>> splitMessageByBoundary(final List<String> message, final String boundary) throws BatchException { final List<List<String>> messageParts = new LinkedList<List<String>>(); @@ -149,15 +148,16 @@ public class BatchParserCommon { } } - static Map<String, HeaderField> consumeHeaders(final List<String> remainingMessage) throws BatchException { + public static Map<String, HeaderField> consumeHeaders(final List<String> remainingMessage) throws BatchException { final Map<String, HeaderField> headers = new HashMap<String, HeaderField>(); boolean isHeader = true; + final Iterator<String> iter = remainingMessage.iterator(); + final AcceptParser acceptParser = new AcceptParser(); String currentLine; - Iterator<String> iter = remainingMessage.iterator(); while (iter.hasNext() && isHeader) { currentLine = iter.next(); - Matcher headerMatcher = REG_EX_HEADER.matcher(currentLine); + Matcher headerMatcher = PATTERN_HEADER_LINE.matcher(currentLine); if (headerMatcher.matches() && headerMatcher.groupCount() == 2) { iter.remove(); @@ -167,38 +167,55 @@ public class BatchParserCommon { String headerValue = headerMatcher.group(2).trim(); if (HttpHeaders.ACCEPT.equalsIgnoreCase(headerNameLowerCase)) { - List<String> acceptHeaders = AcceptParser.parseAcceptHeaders(headerValue); - headers.put(headerNameLowerCase, new HeaderField(headerName, acceptHeaders)); + acceptParser.addAcceptHeaderValue(headerValue); } else if (HttpHeaders.ACCEPT_LANGUAGE.equalsIgnoreCase(headerNameLowerCase)) { - List<String> acceptLanguageHeaders = AcceptParser.parseAcceptableLanguages(headerValue); - headers.put(headerNameLowerCase, new HeaderField(headerName, acceptLanguageHeaders)); + acceptParser.addAcceptLanguageHeaderValue(headerValue); } else { - HeaderField headerField = headers.get(headerNameLowerCase); - headerField = headerField == null ? new HeaderField(headerName) : headerField; - headers.put(headerNameLowerCase, headerField); - headerField.getValues().add(headerValue); + addHeaderValue(headers, headerName, headerNameLowerCase, headerValue); } } else { isHeader = false; } } + final List<String> acceptHeader = acceptParser.parseAcceptHeaders(); + headers.put(HttpHeaders.ACCEPT.toLowerCase(), new HeaderField(HttpHeaders.ACCEPT, acceptHeader)); + + final List<String> acceptLanguageHeader = acceptParser.parseAcceptableLanguages(); + headers.put(HttpHeaders.ACCEPT_LANGUAGE.toLowerCase(), new HeaderField(HttpHeaders.ACCEPT_LANGUAGE, + acceptLanguageHeader)); + return Collections.unmodifiableMap(headers); } - static void consumeBlankLine(final List<String> remainingMessage, final boolean isStrict) throws BatchException { - if (remainingMessage.size() > 0 && "".equals(remainingMessage.get(0).trim())) { - remainingMessage.remove(0); - } else { - if (isStrict) { - throw new BatchException(BatchException.MISSING_BLANK_LINE); + private static void addHeaderValue(final Map<String, HeaderField> headers, final String headerName, + final String headerNameLowerCase, final String headerValue) { + HeaderField headerField = headers.get(headerNameLowerCase); + headerField = headerField == null ? new HeaderField(headerName) : headerField; + headers.put(headerNameLowerCase, headerField); + + for (final String singleValue : splitHeaderValuesByComma(headerValue)) { + if (!headerField.getValues().contains(singleValue)) { + headerField.getValues().add(singleValue); } } } - static void consumeLastBlankLine(final List<String> message, final boolean isStrict) throws BatchException { - if (message.size() > 0 && "".equals(message.get(message.size() - 1).trim())) { - message.remove(message.size() - 1); + private static List<String> splitHeaderValuesByComma(final String headerValue) { + final List<String> singleValues = new ArrayList<String>(); + + String[] parts = headerValue.split(","); + for (final String value : parts) { + singleValues.add(value.trim()); + } + + return singleValues; + } + + public static void consumeBlankLine(final List<String> remainingMessage, final boolean isStrict) + throws BatchException { + if (remainingMessage.size() > 0 && "".equals(remainingMessage.get(0).trim())) { + remainingMessage.remove(0); } else { if (isStrict) { throw new BatchException(BatchException.MISSING_BLANK_LINE); @@ -206,25 +223,22 @@ public class BatchParserCommon { } } - static String getBoundary(final String contentType) throws BatchException { - if (contentType.contains(HttpContentType.MULTIPART_MIXED)) { - String[] parts = contentType.split(BOUNDARY_IDENTIFIER); + public static String getBoundary(final String contentType) throws BatchException { + final Matcher boundaryMatcher = PATTERN_MULTIPART_BOUNDARY.matcher(contentType); - if (parts.length == 2) { - if (parts[1].matches(REG_EX_BOUNDARY)) { - return trimQuota(parts[1].trim()); - } else { - throw new BatchException(BatchException.INVALID_BOUNDARY); - } + if (boundaryMatcher.matches()) { + final String boundary = boundaryMatcher.group(1); + if (boundary.matches(REG_EX_BOUNDARY)) { + return trimQuota(boundary); } else { - throw new BatchException(BatchException.MISSING_PARAMETER_IN_CONTENT_TYPE); + throw new BatchException(BatchException.INVALID_BOUNDARY); } } else { throw new BatchException(BatchException.INVALID_CONTENT_TYPE.addContent(HttpContentType.MULTIPART_MIXED)); } } - static Map<String, List<String>> parseQueryParameter(final String httpRequest) { + public static Map<String, List<String>> parseQueryParameter(final String httpRequest) { Map<String, List<String>> queryParameter = new HashMap<String, List<String>>(); String[] requestParts = httpRequest.split(" "); http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/1f90b733/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchQueryOperation.java ---------------------------------------------------------------------- diff --git a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchQueryOperation.java b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchQueryOperation.java index 179fffb..5176bb8 100644 --- a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchQueryOperation.java +++ b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchQueryOperation.java @@ -27,7 +27,7 @@ import org.apache.olingo.odata2.core.batch.v2.BatchParserCommon.HeaderField; public class BatchQueryOperation implements BatchPart { protected final boolean isStrict; - protected String httpMethod; + protected String httpStatusLine; protected Map<String, HeaderField> headers; protected List<String> body; protected int bodySize; @@ -39,7 +39,7 @@ public class BatchQueryOperation implements BatchPart { } public BatchQueryOperation parse() throws BatchException { - httpMethod = consumeHttpMethod(message); + httpStatusLine = consumeHttpStatusLine(message); headers = BatchParserCommon.consumeHeaders(message); BatchParserCommon.consumeBlankLine(message, isStrict); body = message; @@ -47,7 +47,7 @@ public class BatchQueryOperation implements BatchPart { return this; } - protected String consumeHttpMethod(final List<String> message) throws BatchException { + protected String consumeHttpStatusLine(final List<String> message) throws BatchException { if (message.size() > 0 && !message.get(0).trim().equals("")) { String method = message.get(0); message.remove(0); @@ -58,8 +58,8 @@ public class BatchQueryOperation implements BatchPart { } } - public String getHttpMethod() { - return httpMethod; + public String getHttpStatusLine() { + return httpStatusLine; } public List<String> getBody() { http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/1f90b733/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 3626686..5169575 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 @@ -55,7 +55,6 @@ public class BatchRequestTransformator implements BatchTransformator { final List<ODataRequest> requests = new LinkedList<ODataRequest>(); final List<BatchParserResult> resultList = new ArrayList<BatchParserResult>(); - BatchTransformatorCommon.parsePartSyntax(bodyPart); validateBodyPartHeaders(bodyPart); for (BatchQueryOperation queryOperation : bodyPart.getRequests()) { @@ -77,7 +76,7 @@ public class BatchRequestTransformator implements BatchTransformator { final String baseUri, final BatchQueryOperation queryOperation) throws BatchException { if (bodyPart.isChangeSet()) { - BatchQueryOperation encapsulatedQueryOperation = ((BatchChangeSet) queryOperation).getRequest(); + BatchQueryOperation encapsulatedQueryOperation = ((BatchChangeSetPart) queryOperation).getRequest(); Map<String, HeaderField> headers = transformHeader(encapsulatedQueryOperation, queryOperation); validateChangeSetMultipartMimeHeaders(queryOperation, encapsulatedQueryOperation); @@ -98,7 +97,7 @@ public class BatchRequestTransformator implements BatchTransformator { private ODataRequest createRequest(final BatchQueryOperation operation, final Map<String, HeaderField> headers, final PathInfo pathInfo, final String baseUri, final boolean isChangeSet) throws BatchException { - ODataHttpMethod httpMethod = getHttpMethod(operation.getHttpMethod()); + ODataHttpMethod httpMethod = getHttpMethod(operation.getHttpStatusLine()); validateHttpMethod(httpMethod, isChangeSet); validateBody(httpMethod, operation); InputStream bodyStrean = getBodyStream(operation, headers, httpMethod); @@ -106,10 +105,10 @@ public class BatchRequestTransformator implements BatchTransformator { ODataRequestBuilder requestBuilder = ODataRequest.method(httpMethod) .acceptableLanguages(getAcceptLanguageHeaders(headers)) .acceptHeaders(getAcceptHeaders(headers)) - .allQueryParameters(BatchParserCommon.parseQueryParameter(operation.getHttpMethod())) + .allQueryParameters(BatchParserCommon.parseQueryParameter(operation.getHttpStatusLine())) .body(bodyStrean) .requestHeaders(BatchParserCommon.headerFieldMapToMultiMap(headers)) - .pathInfo(BatchParserCommon.parseRequestUri(operation.getHttpMethod(), pathInfo, baseUri)); + .pathInfo(BatchParserCommon.parseRequestUri(operation.getHttpStatusLine(), pathInfo, baseUri)); addContentTypeHeader(requestBuilder, headers); @@ -135,9 +134,12 @@ public class BatchRequestTransformator implements BatchTransformator { return new ByteArrayInputStream(new byte[0]); } else { int contentLength = BatchTransformatorCommon.getContentLength(headers); - contentLength = (contentLength >= 0) ? contentLength : Integer.MAX_VALUE; - return BatchParserCommon.convertMessageToInputStream(operation.getBody(), contentLength); + if (contentLength == -1) { + return BatchParserCommon.convertMessageToInputStream(operation.getBody()); + } else { + return BatchParserCommon.convertMessageToInputStream(operation.getBody(), contentLength); + } } } http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/1f90b733/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 88f5064..d82d09e 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 @@ -51,7 +51,6 @@ public class BatchResponseTransformator implements BatchTransformator { List<BatchParserResult> resultList = new ArrayList<BatchParserResult>(); - BatchTransformatorCommon.parsePartSyntax(bodyPart); BatchTransformatorCommon.validateContentType(bodyPart.getHeaders()); resultList.addAll(handleBodyPart(bodyPart)); @@ -64,7 +63,7 @@ public class BatchResponseTransformator implements BatchTransformator { if (bodyPart.isChangeSet()) { for (BatchQueryOperation operation : bodyPart.getRequests()) { - bodyPartResult.add(transformChangeSet((BatchChangeSet) operation)); + bodyPartResult.add(transformChangeSet((BatchChangeSetPart) operation)); } } else { bodyPartResult.add(transformQueryOperation(bodyPart.getRequests().get(0), getContentId(bodyPart.getHeaders()))); @@ -73,7 +72,7 @@ public class BatchResponseTransformator implements BatchTransformator { return bodyPartResult; } - private BatchSingleResponse transformChangeSet(final BatchChangeSet changeSet) throws BatchException { + private BatchSingleResponse transformChangeSet(final BatchChangeSetPart changeSet) throws BatchException { BatchTransformatorCommon.validateContentTransferEncoding(changeSet.getHeaders(), true); return transformQueryOperation(changeSet.getRequest(), getContentId(changeSet.getHeaders())); @@ -84,8 +83,8 @@ public class BatchResponseTransformator implements BatchTransformator { BatchSingleResponseImpl response = new BatchSingleResponseImpl(); response.setContentId(contentId); response.setHeaders(BatchParserCommon.headerFieldMapToSingleMap(operation.getHeaders())); - response.setStatusCode(getStatusCode(operation.httpMethod)); - response.setStatusInfo(getStatusInfo(operation.getHttpMethod())); + response.setStatusCode(getStatusCode(operation.httpStatusLine)); + response.setStatusInfo(getStatusInfo(operation.getHttpStatusLine())); response.setBody(getBody(operation)); return response; @@ -105,8 +104,8 @@ public class BatchResponseTransformator implements BatchTransformator { private String getBody(final BatchQueryOperation operation) throws BatchException { int contentLength = BatchTransformatorCommon.getContentLength(operation.getHeaders()); - List<String> body = BatchParserCommon.trimStringListToLength(operation.getBody(), contentLength); - return BatchParserCommon.stringListToString(body); + + return BatchParserCommon.trimStringListToStringLength(operation.getBody(), contentLength); } private String getStatusCode(final String httpMethod) throws BatchException { http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/1f90b733/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 2098708..c9c8e0f 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 @@ -12,20 +12,16 @@ import org.apache.olingo.odata2.core.batch.v2.BatchParserCommon.HeaderField; public class BatchTransformatorCommon { public static void validateContentType(final Map<String, HeaderField> headers) throws BatchException { - if (headers.containsKey(HttpHeaders.CONTENT_TYPE.toLowerCase(Locale.ENGLISH))) { - HeaderField contentTypeField = headers.get(HttpHeaders.CONTENT_TYPE.toLowerCase(Locale.ENGLISH)); - + final HeaderField contentTypeField = headers.get(HttpHeaders.CONTENT_TYPE.toLowerCase(Locale.ENGLISH)); + if (contentTypeField != null) { if (contentTypeField.getValues().size() == 1) { - String contentType = contentTypeField.getValues().get(0); - - if (!(HttpContentType.APPLICATION_HTTP.equalsIgnoreCase(contentType) - || contentType.contains(HttpContentType.MULTIPART_MIXED))) { + final String contentType = contentTypeField.getValues().get(0); + if (!BatchParserCommon.PATTERN_MULTIPART_BOUNDARY.matcher(contentType).matches() + && !BatchParserCommon.PATTERN_CONTENT_TYPE_APPLICATION_HTTP.matcher(contentType).matches()) { throw new BatchException(BatchException.INVALID_CONTENT_TYPE.addContent(HttpContentType.MULTIPART_MIXED + " or " + HttpContentType.APPLICATION_HTTP)); } - } else if (contentTypeField.getValues().size() == 0) { - throw new BatchException(BatchException.MISSING_CONTENT_TYPE); } else { throw new BatchException(BatchException.INVALID_HEADER); } @@ -34,7 +30,8 @@ public class BatchTransformatorCommon { } } - public static void validateContentTransferEncoding(final Map<String, HeaderField> headers, boolean isChangeRequest) + public static void validateContentTransferEncoding(final Map<String, HeaderField> headers, + final boolean isChangeRequest) throws BatchException { if (headers.containsKey(BatchHelper.HTTP_CONTENT_TRANSFER_ENCODING.toLowerCase(Locale.ENGLISH))) { HeaderField encodingField = headers.get(BatchHelper.HTTP_CONTENT_TRANSFER_ENCODING.toLowerCase(Locale.ENGLISH)); @@ -57,11 +54,6 @@ public class BatchTransformatorCommon { } } - public static void parsePartSyntax(final BatchBodyPart bodyPart) throws BatchException { - int contentLength = BatchTransformatorCommon.getContentLength(bodyPart.getHeaders()); - bodyPart.parse(contentLength); - } - public static int getContentLength(final Map<String, HeaderField> headers) throws BatchException { if (headers.containsKey(HttpHeaders.CONTENT_LENGTH.toLowerCase(Locale.ENGLISH))) { @@ -79,6 +71,6 @@ public class BatchTransformatorCommon { } } - return Integer.MAX_VALUE; + return -1; } } http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/1f90b733/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/AcceptParserTest.java ---------------------------------------------------------------------- diff --git a/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/AcceptParserTest.java b/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/AcceptParserTest.java index a3c0512..b7d7fac 100644 --- a/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/AcceptParserTest.java +++ b/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/AcceptParserTest.java @@ -31,8 +31,10 @@ public class AcceptParserTest { @Test public void testAcceptHeader() throws BatchException { - List<String> acceptHeaders = - AcceptParser.parseAcceptHeaders("text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"); + AcceptParser parser = new AcceptParser(); + parser.addAcceptHeaderValue("text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"); + List<String> acceptHeaders = parser.parseAcceptHeaders(); + assertNotNull(acceptHeaders); assertEquals(4, acceptHeaders.size()); assertEquals("text/html", acceptHeaders.get(0)); @@ -43,48 +45,58 @@ public class AcceptParserTest { @Test public void testAcceptHeaderWithParameter() throws BatchException { - List<String> acceptHeaders = AcceptParser.parseAcceptHeaders("application/json;odata=verbose;q=1.0, */*;q=0.1"); + AcceptParser parser = new AcceptParser(); + parser.addAcceptHeaderValue("application/json;odata=verbose;q=1.0, */*;q=0.1"); + List<String> acceptHeaders = parser.parseAcceptHeaders(); + assertNotNull(acceptHeaders); assertEquals(2, acceptHeaders.size()); assertEquals("application/json;odata=verbose", acceptHeaders.get(0)); - ; assertEquals("*/*", acceptHeaders.get(1)); } @Test public void testAcceptHeaderWithParameterAndLws() throws BatchException { - List<String> acceptHeaders = AcceptParser.parseAcceptHeaders("application/json; odata=verbose;q=1.0, */*;q=0.1"); + AcceptParser parser = new AcceptParser(); + parser.addAcceptHeaderValue("application/json; odata=verbose;q=1.0, */*;q=0.1"); + List<String> acceptHeaders = parser.parseAcceptHeaders(); + assertNotNull(acceptHeaders); assertEquals(2, acceptHeaders.size()); assertEquals("application/json; odata=verbose", acceptHeaders.get(0)); - ; assertEquals("*/*", acceptHeaders.get(1)); } @Test public void testAcceptHeaderWithTabulator() throws BatchException { - List<String> acceptHeaders = AcceptParser.parseAcceptHeaders("application/json;\todata=verbose;q=1.0, */*;q=0.1"); + AcceptParser parser = new AcceptParser(); + parser.addAcceptHeaderValue("application/json;\todata=verbose;q=1.0, */*;q=0.1"); + List<String> acceptHeaders = parser.parseAcceptHeaders(); + assertNotNull(acceptHeaders); assertEquals(2, acceptHeaders.size()); assertEquals("application/json;" + TAB + "odata=verbose", acceptHeaders.get(0)); - ; assertEquals("*/*", acceptHeaders.get(1)); } @Test public void testAcceptHeaderWithTwoParameters() throws BatchException { - List<String> acceptHeaders = - AcceptParser.parseAcceptHeaders("application/xml;another=test ; param=alskdf, */*;q=0.1"); + AcceptParser parser = new AcceptParser(); + parser.addAcceptHeaderValue("application/xml;another=test ; param=alskdf, */*;q=0.1"); + List<String> acceptHeaders = parser.parseAcceptHeaders(); + assertNotNull(acceptHeaders); assertEquals(2, acceptHeaders.size()); assertEquals("application/xml;another=test ; param=alskdf", acceptHeaders.get(0)); - ; assertEquals("*/*", acceptHeaders.get(1)); } @Test public void testAcceptHeader2() throws BatchException { - List<String> acceptHeaders = AcceptParser.parseAcceptHeaders("text/html;level=1, application/*, */*;q=0.1"); + AcceptParser parser = new AcceptParser(); + parser.addAcceptHeaderValue("text/html;level=1, application/*, */*;q=0.1"); + List<String> acceptHeaders = parser.parseAcceptHeaders(); + assertNotNull(acceptHeaders); assertEquals(3, acceptHeaders.size()); assertEquals("text/html;level=1", acceptHeaders.get(0)); @@ -94,7 +106,10 @@ public class AcceptParserTest { @Test public void testMoreSpecificMediaType() throws BatchException { - List<String> acceptHeaders = AcceptParser.parseAcceptHeaders("application/*, application/xml"); + AcceptParser parser = new AcceptParser(); + parser.addAcceptHeaderValue("application/*, application/xml"); + List<String> acceptHeaders = parser.parseAcceptHeaders(); + assertNotNull(acceptHeaders); assertEquals(2, acceptHeaders.size()); assertEquals("application/xml", acceptHeaders.get(0)); @@ -103,28 +118,40 @@ public class AcceptParserTest { @Test public void testQualityParameter() throws BatchException { - List<String> acceptHeaders = AcceptParser.parseAcceptHeaders("application/*, */*; q=0.012"); + AcceptParser parser = new AcceptParser(); + parser.addAcceptHeaderValue("application/*, */*; q=0.012"); + List<String> acceptHeaders = parser.parseAcceptHeaders(); + assertNotNull(acceptHeaders); } @Test(expected = BatchException.class) public void testInvalidAcceptHeader() throws BatchException { - AcceptParser.parseAcceptHeaders("appi cation/*, */*;q=0.1"); + AcceptParser parser = new AcceptParser(); + parser.addAcceptHeaderValue("appi cation/*, */*;q=0.1"); + parser.parseAcceptHeaders(); } @Test(expected = BatchException.class) public void testInvalidQualityParameter() throws BatchException { - AcceptParser.parseAcceptHeaders("appication/*, */*;q=0,9"); + AcceptParser parser = new AcceptParser(); + parser.addAcceptHeaderValue("appication/*, */*;q=0,9"); + parser.parseAcceptHeaders(); } @Test(expected = BatchException.class) public void testInvalidQualityParameter2() throws BatchException { - AcceptParser.parseAcceptHeaders("appication/*, */*;q=1.0001"); + AcceptParser parser = new AcceptParser(); + parser.addAcceptHeaderValue("appication/*, */*;q=1.0001"); + parser.parseAcceptHeaders(); } @Test public void testAcceptLanguages() throws BatchException { - List<String> acceptLanguageHeaders = AcceptParser.parseAcceptableLanguages("en-US,en;q=0.7,en-UK;q=0.9"); + AcceptParser parser = new AcceptParser(); + parser.addAcceptLanguageHeaderValue("en-US,en;q=0.7,en-UK;q=0.9"); + List<String> acceptLanguageHeaders = parser.parseAcceptableLanguages(); + assertNotNull(acceptLanguageHeaders); assertEquals(3, acceptLanguageHeaders.size()); assertEquals("en-US", acceptLanguageHeaders.get(0)); @@ -134,20 +161,28 @@ public class AcceptParserTest { @Test public void testAllAcceptLanguages() throws BatchException { - List<String> acceptLanguageHeaders = AcceptParser.parseAcceptableLanguages("*"); + AcceptParser parser = new AcceptParser(); + parser.addAcceptLanguageHeaderValue("*"); + List<String> acceptLanguageHeaders = parser.parseAcceptableLanguages(); + assertNotNull(acceptLanguageHeaders); assertEquals(1, acceptLanguageHeaders.size()); } @Test public void testLongAcceptLanguageValue() throws BatchException { - List<String> acceptLanguageHeaders = AcceptParser.parseAcceptableLanguages("english"); + AcceptParser parser = new AcceptParser(); + parser.addAcceptLanguageHeaderValue("english"); + List<String> acceptLanguageHeaders = parser.parseAcceptableLanguages(); + assertNotNull(acceptLanguageHeaders); assertEquals("english", acceptLanguageHeaders.get(0)); } @Test(expected = BatchException.class) public void testInvalidAcceptLanguageValue() throws BatchException { - AcceptParser.parseAcceptableLanguages("en_US"); + AcceptParser parser = new AcceptParser(); + parser.addAcceptLanguageHeaderValue("en_US"); + parser.parseAcceptableLanguages(); } } http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/1f90b733/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchParserCommonTest.java ---------------------------------------------------------------------- diff --git a/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchParserCommonTest.java b/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchParserCommonTest.java index c9e9a6b..8451c55 100644 --- a/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchParserCommonTest.java +++ b/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchParserCommonTest.java @@ -1,54 +1,170 @@ package org.apache.olingo.odata2.core.batch; -import static org.junit.Assert.assertEquals; +import static org.junit.Assert.*; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Locale; +import java.util.Map; +import org.apache.olingo.odata2.api.batch.BatchException; +import org.apache.olingo.odata2.api.commons.HttpHeaders; import org.apache.olingo.odata2.core.batch.v2.BatchParserCommon; +import org.apache.olingo.odata2.core.batch.v2.BatchParserCommon.HeaderField; import org.junit.Test; public class BatchParserCommonTest { - + + private static final String CRLF = "\r\n"; + @Test - public void testTrimList() { - final List<String> list = Arrays.asList(new String[] { "123\r\n", "abc", "a\n", "\r", "123" }); - final List<String> trimedList = BatchParserCommon.trimStringListToLength(list, 7); - - assertEquals(2, trimedList.size()); - assertEquals("123\r\n", trimedList.get(0)); - assertEquals("ab", trimedList.get(1)); + public void testMultipleHeader() throws BatchException { + String[] messageRaw = new String[] { + "Content-Id: 1" + CRLF, + "Content-Id: 2" + CRLF, + "content-type: Application/http" + CRLF, + "content-transfer-encoding: Binary" + CRLF + }; + List<String> message = new ArrayList<String>(); + message.addAll(Arrays.asList(messageRaw)); + + + final Map<String, HeaderField> header = BatchParserCommon.consumeHeaders(message); + assertNotNull(header); + + final HeaderField contentIdHeaders = header.get(BatchHelper.HTTP_CONTENT_ID.toLowerCase(Locale.ENGLISH)); + assertNotNull(contentIdHeaders); + assertEquals(2, contentIdHeaders.getValues().size()); + assertEquals("1", contentIdHeaders.getValues().get(0)); + assertEquals("2", contentIdHeaders.getValues().get(1)); } - + @Test - public void testTrimListWithEmptyString() { - final List<String> list = Arrays.asList(new String[] { "123\r\n", "", "abc", "a\n", "\r", "123" }); - final List<String> trimedList = BatchParserCommon.trimStringListToLength(list, 7); - - assertEquals(3, trimedList.size()); - assertEquals("123\r\n", trimedList.get(0)); - assertEquals("", trimedList.get(1)); - assertEquals("ab", trimedList.get(2)); + public void testMultipleHeaderSameValue() throws BatchException { + String[] messageRaw = new String[] { + "Content-Id: 1" + CRLF, + "Content-Id: 1" + CRLF, + "content-type: Application/http" + CRLF, + "content-transfer-encoding: Binary" + CRLF + }; + List<String> message = new ArrayList<String>(); + message.addAll(Arrays.asList(messageRaw)); + + + final Map<String, HeaderField> header = BatchParserCommon.consumeHeaders(message); + assertNotNull(header); + + final HeaderField contentIdHeaders = header.get(BatchHelper.HTTP_CONTENT_ID.toLowerCase(Locale.ENGLISH)); + assertNotNull(contentIdHeaders); + assertEquals(1, contentIdHeaders.getValues().size()); + assertEquals("1", contentIdHeaders.getValues().get(0)); } - + @Test - public void testTrimListTryToReadMoreThanStringLength() { - final List<String> list = Arrays.asList(new String[] { "abc\r\n", "123" }); - final List<String> trimedList = BatchParserCommon.trimStringListToLength(list, 100); - - assertEquals(2, trimedList.size()); - assertEquals("abc\r\n", trimedList.get(0)); - assertEquals("123", trimedList.get(1)); + public void testHeaderSperatedByComma() throws BatchException { + String[] messageRaw = new String[] { + "Content-Id: 1" + CRLF, + "Upgrade: HTTP/2.0, SHTTP/1.3, IRC/6.9, RTA/x11" + CRLF, + "content-type: Application/http" + CRLF, + "content-transfer-encoding: Binary" + CRLF + }; + List<String> message = new ArrayList<String>(); + message.addAll(Arrays.asList(messageRaw)); + + + final Map<String, HeaderField> header = BatchParserCommon.consumeHeaders(message); + assertNotNull(header); + + final HeaderField upgradeHeader = header.get("upgrade"); + assertNotNull(upgradeHeader); + assertEquals(4, upgradeHeader.getValues().size()); + assertEquals("HTTP/2.0", upgradeHeader.getValues().get(0)); + assertEquals("SHTTP/1.3", upgradeHeader.getValues().get(1)); + assertEquals("IRC/6.9", upgradeHeader.getValues().get(2)); + assertEquals("RTA/x11", upgradeHeader.getValues().get(3)); } - + @Test - public void testTrimListEmpty() { - final List<String> list = Arrays.asList(new String[0]); - final List<String> trimedList = BatchParserCommon.trimStringListToLength(list, 7); - - assertEquals(0, trimedList.size()); + public void testMultipleAcceptHeader() throws BatchException { + String[] messageRaw = new String[] { + "Accept: application/atomsvc+xml;q=0.8, application/json;odata=verbose;q=0.5, */*;q=0.1" + CRLF, + "Accept: text/plain;q=0.3" + CRLF, + "Accept-Language:en-US,en;q=0.7,en-UK;q=0.9" + CRLF, + "content-type: Application/http" + CRLF, + "content-transfer-encoding: Binary" + CRLF + }; + List<String> message = new ArrayList<String>(); + message.addAll(Arrays.asList(messageRaw)); + + + final Map<String, HeaderField> header = BatchParserCommon.consumeHeaders(message); + assertNotNull(header); + + final HeaderField acceptHeader = header.get(HttpHeaders.ACCEPT.toLowerCase()); + assertNotNull(acceptHeader); + assertEquals(4, acceptHeader.getValues().size()); } - + + @Test + public void testMultipleAcceptHeaderSameValue() throws BatchException { + String[] messageRaw = new String[] { + "Accept: application/atomsvc+xml;q=0.8, application/json;odata=verbose;q=0.5, */*;q=0.1" + CRLF, + "Accept: application/atomsvc+xml;q=0.8" + CRLF, + "Accept-Language:en-US,en;q=0.7,en-UK;q=0.9" + CRLF, + "content-type: Application/http" + CRLF, + "content-transfer-encoding: Binary" + CRLF + }; + List<String> message = new ArrayList<String>(); + message.addAll(Arrays.asList(messageRaw)); + + + final Map<String, HeaderField> header = BatchParserCommon.consumeHeaders(message); + assertNotNull(header); + + final HeaderField acceptHeader = header.get(HttpHeaders.ACCEPT.toLowerCase()); + assertNotNull(acceptHeader); + assertEquals(3, acceptHeader.getValues().size()); + } + + @Test + public void testMultipleAccepLanguagetHeader() throws BatchException { + String[] messageRaw = new String[] { + "Accept-Language:en-US,en;q=0.7,en-UK;q=0.9" + CRLF, + "Accept-Language: de-DE;q=0.3" + CRLF, + "content-type: Application/http" + CRLF, + "content-transfer-encoding: Binary" + CRLF + }; + List<String> message = new ArrayList<String>(); + message.addAll(Arrays.asList(messageRaw)); + + final Map<String, HeaderField> header = BatchParserCommon.consumeHeaders(message); + assertNotNull(header); + + final HeaderField acceptLanguageHeader = header.get(HttpHeaders.ACCEPT_LANGUAGE.toLowerCase()); + assertNotNull(acceptLanguageHeader); + assertEquals(4, acceptLanguageHeader.getValues().size()); + } + + @Test + public void testMultipleAccepLanguagetHeaderSameValue() throws BatchException { + String[] messageRaw = new String[] { + "Accept-Language:en-US,en;q=0.7,en-UK;q=0.9" + CRLF, + "Accept-Language:en-US,en;q=0.7" + CRLF, + "content-type: Application/http" + CRLF, + "content-transfer-encoding: Binary" + CRLF + }; + List<String> message = new ArrayList<String>(); + message.addAll(Arrays.asList(messageRaw)); + + final Map<String, HeaderField> header = BatchParserCommon.consumeHeaders(message); + assertNotNull(header); + + final HeaderField acceptLanguageHeader = header.get(HttpHeaders.ACCEPT_LANGUAGE.toLowerCase()); + assertNotNull(acceptLanguageHeader); + assertEquals(3, acceptLanguageHeader.getValues().size()); + } + @Test public void testRemoveEndingCRLF() { String line = "Test\r\n"; http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/1f90b733/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 7866004..4cd0b67 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 @@ -431,7 +431,7 @@ public class BatchRequestParserTest { + "--batch_8194-cf13-1f56--"; parseInvalidBatchBody(batch); } - + @Test(expected = BatchException.class) public void testMissingContentTransferEncoding() throws BatchException { String batch = "--batch_8194-cf13-1f56" + CRLF @@ -439,7 +439,7 @@ public class BatchRequestParserTest { + CRLF + "--changeset_f980-1cb6-94dd" + CRLF + "Content-Type: application/http" + CRLF - //+ "Content-Transfer-Encoding: binary" + CRLF + // + "Content-Transfer-Encoding: binary" + CRLF + CRLF + "POST Employees('2') HTTP/1.1" + CRLF + "Content-Type: application/json;odata=verbose" + CRLF @@ -449,14 +449,14 @@ public class BatchRequestParserTest { + "--batch_8194-cf13-1f56--"; parseInvalidBatchBody(batch); } - + @Test(expected = BatchException.class) public void testMissingContentType() 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 - //+ "Content-Type: application/http" + CRLF + // + "Content-Type: application/http" + CRLF + "Content-Transfer-Encoding: binary" + CRLF + CRLF + "POST Employees('2') HTTP/1.1" + CRLF @@ -467,7 +467,7 @@ public class BatchRequestParserTest { + "--batch_8194-cf13-1f56--"; parseInvalidBatchBody(batch); } - + @Test(expected = BatchException.class) public void testNoCloseDelimiter() throws BatchException { String batch = "--batch_8194-cf13-1f56" + CRLF @@ -605,32 +605,33 @@ public class BatchRequestParserTest { } } - + @SuppressWarnings("unused") - @Test(expected=BatchException.class) + @Test(expected = BatchException.class) + @Ignore("This header should not be validated") public void testNegativeContentLength() throws BatchException, IOException { - String batch = "" - + "--batch_8194-cf13-1f56" + CRLF - + "Content-Type: multipart/mixed; boundary=changeset_f980-1cb6-94dd" + CRLF - + "Content-Length: -2" + CRLF - + CRLF - + "--changeset_f980-1cb6-94dd" + CRLF - + MIME_HEADERS - + "Content-ID: " + PUT_MIME_HEADER_CONTENT_ID + CRLF - + CRLF - + "PUT $" + CONTENT_ID_REFERENCE + "/EmployeeName HTTP/1.1" + CRLF - + "Content-Type: application/json;odata=verbose" + CRLF - + "Content-Id:" + PUT_REQUEST_HEADER_CONTENT_ID + CRLF - + CRLF - + "{\"EmployeeName\":\"Peter Fall\"}" + CRLF - + "--changeset_f980-1cb6-94dd--" + CRLF - + CRLF - + "--batch_8194-cf13-1f56--"; - InputStream in = new ByteArrayInputStream(batch.getBytes()); - BatchParser parser = new BatchParser(contentType, batchProperties, true); - List<BatchRequestPart> batchRequestParts = parser.parseBatchRequest(in); + String batch = "" + + "--batch_8194-cf13-1f56" + CRLF + + "Content-Type: multipart/mixed; boundary=changeset_f980-1cb6-94dd" + CRLF + + "Content-Length: -2" + CRLF + + CRLF + + "--changeset_f980-1cb6-94dd" + CRLF + + MIME_HEADERS + + "Content-ID: " + PUT_MIME_HEADER_CONTENT_ID + CRLF + + CRLF + + "PUT $" + CONTENT_ID_REFERENCE + "/EmployeeName HTTP/1.1" + CRLF + + "Content-Type: application/json;odata=verbose" + CRLF + + "Content-Id:" + PUT_REQUEST_HEADER_CONTENT_ID + CRLF + + CRLF + + "{\"EmployeeName\":\"Peter Fall\"}" + CRLF + + "--changeset_f980-1cb6-94dd--" + CRLF + + CRLF + + "--batch_8194-cf13-1f56--"; + InputStream in = new ByteArrayInputStream(batch.getBytes()); + BatchParser parser = new BatchParser(contentType, batchProperties, true); + List<BatchRequestPart> batchRequestParts = parser.parseBatchRequest(in); } - + @SuppressWarnings("unused") @Test public void testNegativeContentLengthChangeSet() throws BatchException, IOException { @@ -655,9 +656,9 @@ public class BatchRequestParserTest { BatchParser parser = new BatchParser(contentType, batchProperties, true); List<BatchRequestPart> batchRequestParts = parser.parseBatchRequest(in); } - + @SuppressWarnings("unused") - @Test(expected=BatchException.class) + @Test(expected = BatchException.class) public void testNegativeContentLengthRequest() throws BatchException, IOException { String batch = "" + "--batch_8194-cf13-1f56" + CRLF @@ -680,7 +681,7 @@ public class BatchRequestParserTest { BatchParser parser = new BatchParser(contentType, batchProperties, true); List<BatchRequestPart> batchRequestParts = parser.parseBatchRequest(in); } - + @Test public void testContentLengthGreatherThanBodyLength() throws BatchException, IOException { String batch = "" @@ -746,6 +747,7 @@ public class BatchRequestParserTest { } @Test(expected = BatchException.class) + @Ignore("This header should not be validated") public void testCutChangeSetDelimiter() throws BatchException, IOException { String batch = "" + "--batch_8194-cf13-1f56" + CRLF @@ -918,7 +920,7 @@ public class BatchRequestParserTest { } } } - + @Test public void testNoContentId() throws BatchException { String batch = "--batch_8194-cf13-1f56" + CRLF @@ -950,10 +952,10 @@ public class BatchRequestParserTest { + "--batch_8194-cf13-1f56--"; InputStream in = new ByteArrayInputStream(batch.getBytes()); BatchParser parser = new BatchParser(contentType, batchProperties, true); - List<BatchRequestPart> batchRequestParts = parser.parseBatchRequest(in); // No exception should be thrown + List<BatchRequestPart> batchRequestParts = parser.parseBatchRequest(in); // No exception should be thrown assertNotNull(batchRequestParts); } - + @Test public void testPreamble() throws BatchException, IOException { String batch = "" @@ -1017,6 +1019,60 @@ public class BatchRequestParserTest { inputStreamToString(changeSetPart.getRequests().get(1).getBody())); } + @SuppressWarnings("unused") + @Test + public void testContentTypeCaseInsensitive() throws BatchException, IOException { + 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 + + "Content-ID: " + PUT_MIME_HEADER_CONTENT_ID + CRLF + + "Content-Length: -2" + CRLF + + CRLF + + "PUT $" + CONTENT_ID_REFERENCE + "/EmployeeName HTTP/1.1" + CRLF + + "Content-Type: application/json;odata=verbose" + CRLF + + "Content-Id:" + PUT_REQUEST_HEADER_CONTENT_ID + CRLF + + CRLF + + "{\"EmployeeName\":\"Peter Fall\"}" + CRLF + + "--changeset_f980-1cb6-94dd--" + CRLF + + CRLF + + "--batch_8194-cf13-1f56--"; + InputStream in = new ByteArrayInputStream(batch.getBytes()); + BatchParser parser = new BatchParser(contentType, batchProperties, true); + List<BatchRequestPart> batchRequestParts = parser.parseBatchRequest(in); + } + + @Test + public void testContentTypeBoundaryCaseInsensitive() throws BatchException, IOException { + 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 + + "Content-ID: " + PUT_MIME_HEADER_CONTENT_ID + CRLF + + "Content-Length: -2" + CRLF + + CRLF + + "PUT $" + CONTENT_ID_REFERENCE + "/EmployeeName HTTP/1.1" + CRLF + + "Content-Type: application/json;odata=verbose" + CRLF + + "Content-Id:" + PUT_REQUEST_HEADER_CONTENT_ID + CRLF + + CRLF + + "{\"EmployeeName\":\"Peter Fall\"}" + CRLF + + "--changeset_f980-1cb6-94dd--" + CRLF + + CRLF + + "--batch_8194-cf13-1f56--"; + InputStream in = new ByteArrayInputStream(batch.getBytes()); + BatchParser parser = new BatchParser(contentType, batchProperties, true); + List<BatchRequestPart> batchRequestParts = parser.parseBatchRequest(in); + + assertNotNull(batchRequestParts); + assertEquals(1, batchRequestParts.size()); + assertTrue(batchRequestParts.get(0).isChangeSet()); + assertEquals(1, batchRequestParts.get(0).getRequests().size()); + } + @Test public void testEpilog() throws BatchException, IOException { String batch = "" http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/1f90b733/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchTransformatorCommonTest.java ---------------------------------------------------------------------- diff --git a/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchTransformatorCommonTest.java b/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchTransformatorCommonTest.java index a0ab9f4..a70d15a 100644 --- a/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchTransformatorCommonTest.java +++ b/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchTransformatorCommonTest.java @@ -26,7 +26,17 @@ public class BatchTransformatorCommonTest { @Test public void testValidateContentTypeMultipartMixed() throws BatchException { - List<String> contentTypeValues = Arrays.asList(new String[] { HttpContentType.MULTIPART_MIXED }); + List<String> contentTypeValues = + Arrays.asList(new String[] { HttpContentType.MULTIPART_MIXED + "; boundary=batch_32332_32323_fdsf" }); + Map<String, HeaderField> headers = makeHeaders(HttpHeaders.CONTENT_TYPE, contentTypeValues); + + BatchTransformatorCommon.validateContentType(headers); + } + + @Test + public void testValidateContentTypeMultipartMixedCaseInsensitiv() throws BatchException { + List<String> contentTypeValues = + Arrays.asList(new String[] { "mulTiPart/MiXed; boundary=batch_32332_32323_fdsf" }); Map<String, HeaderField> headers = makeHeaders(HttpHeaders.CONTENT_TYPE, contentTypeValues); BatchTransformatorCommon.validateContentType(headers);
