diff options
Diffstat (limited to 'bundles/org.eclipse.wst.wsi/src/org/eclipse/wst/wsi/internal/core/profile/validator/impl/message/AP1935.java')
-rw-r--r-- | bundles/org.eclipse.wst.wsi/src/org/eclipse/wst/wsi/internal/core/profile/validator/impl/message/AP1935.java | 348 |
1 files changed, 348 insertions, 0 deletions
diff --git a/bundles/org.eclipse.wst.wsi/src/org/eclipse/wst/wsi/internal/core/profile/validator/impl/message/AP1935.java b/bundles/org.eclipse.wst.wsi/src/org/eclipse/wst/wsi/internal/core/profile/validator/impl/message/AP1935.java new file mode 100644 index 000000000..4d8fce7fc --- /dev/null +++ b/bundles/org.eclipse.wst.wsi/src/org/eclipse/wst/wsi/internal/core/profile/validator/impl/message/AP1935.java @@ -0,0 +1,348 @@ +/******************************************************************************* + * Copyright (c) 2002-2005 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM - Initial API and implementation + *******************************************************************************/ +package org.eclipse.wst.wsi.internal.core.profile.validator.impl.message; + +import java.util.ArrayList; +import java.util.Iterator; + +import org.eclipse.wst.wsi.internal.core.WSIException; +import org.eclipse.wst.wsi.internal.core.analyzer.AssertionFailException; +import org.eclipse.wst.wsi.internal.core.log.MimePart; +import org.eclipse.wst.wsi.internal.core.log.MimeParts; +import org.eclipse.wst.wsi.internal.core.profile.TestAssertion; +import org.eclipse.wst.wsi.internal.core.profile.validator.EntryContext; +import org.eclipse.wst.wsi.internal.core.profile.validator.impl.AssertionProcess; +import org.eclipse.wst.wsi.internal.core.profile.validator.impl.BaseMessageValidator; +import org.eclipse.wst.wsi.internal.core.report.AssertionResult; +import org.eclipse.wst.wsi.internal.core.util.HTTPConstants; +import org.eclipse.wst.wsi.internal.core.util.HTTPUtils; +import org.eclipse.wst.wsi.internal.core.util.Utils; + +/** + * AP1935 + * + * <context>For a candidate part of a multipart/related message</context> + * <assertionDescription>The encoding of the body of a part in a + * multipart/related message conforms to the encoding indicated by the + * Content-Transfer-Encoding field-value, + * as specified by RFC2045.</assertionDescription> + */ +public class AP1935 extends AssertionProcess +{ + private final BaseMessageValidator validator; + + /** + * @param WSDLValidatorImpl + */ + public AP1935(BaseMessageValidator impl) + { + super(impl); + this.validator = impl; + } + + /* Validates the test assertion. + * @see org.wsi.test.profile.validator.impl.BaseValidatorImpl.AssertionProcess#validate(org.wsi.test.profile.TestAssertion, org.wsi.test.profile.validator.EntryContext) + */ + public AssertionResult validate( + TestAssertion testAssertion, + EntryContext entryContext) + throws WSIException + { + if(!entryContext.getMessageEntry().isMimeContent()) + { + result = AssertionResult.RESULT_NOT_APPLICABLE; + } + else + { + // get MIME parts + MimeParts parts = entryContext.getMessageEntry().getMimeParts(); + if(parts.count() == 0) + { + result = AssertionResult.RESULT_NOT_APPLICABLE; + } + else + { + // check each part for the encoding match + Iterator iparts = parts.getParts().iterator(); + int i = 0; + MimePart root = parts.getRootPart(); + while (iparts.hasNext()) + { + i = i = 1; + try + { + MimePart part = (MimePart)iparts.next(); + + // get encoding from header + String encoding = HTTPUtils.getHttpHeaderAttribute(part.getHeaders(), + HTTPConstants.HEADER_CONTENT_TRANSFER_ENCODING); + + if ((part == root) || + ((encoding != null) && encoding.equalsIgnoreCase("base64"))) + checkPart(part, encoding, false); + else + checkPart(part, encoding, true); + } catch (AssertionFailException e) + { + result = AssertionResult.RESULT_FAILED; + failureDetail = validator.createFailureDetail( + "part "+(i+1)+" Error: " + e.getMessage(), entryContext); + } + } + } + } + // Return assertion result + return validator.createAssertionResult( + testAssertion, result, failureDetail); + } + /** + * Check message entry to encoding conformity + * @param entry message entry + * @throws AssertionFailException if message does not encoding conformity + * @throws WSIException + */ + private void checkPart(MimePart part, String encoding, boolean encoded) + throws AssertionFailException, WSIException + { + String content = null; + if (encoded) + content = new String(Utils.decodeBase64(part.getContent())); + else + content = part.getContent(); + + if(encoding == null) + { + result = AssertionResult.RESULT_NOT_APPLICABLE; + // check 7bit + } else if(encoding.equalsIgnoreCase("7bit")) { + checkOn7bit(content); + // check 8bit + } else if(encoding.equalsIgnoreCase("8bit")) { + checkOn8bit(content); + // check quoted-printable + } else if(encoding.equalsIgnoreCase("quoted-printable")) { + checkOnQuotedPrintable(content); + // check base64 + } else if(encoding.equalsIgnoreCase("base64")) { + checkOnBase64(content); + } + // we dont check binary encoding, since message can contains any chars + } + + /** + * Validate a 7bit encoded message (RFC2045) + * @param message message to check + * @throws AssertionFailException if message does not conform + */ + private void checkOn7bit(String message) + throws AssertionFailException + { + String[] strs = split(message); + for (int i = 0; i < strs.length; i++) + { + String str = strs[i]; + + // check string length + if(str.length() > 998) + { + throw new AssertionFailException("The length (" + str.length() + + ") of the line (" + (i+1) + ") greater than 998"); + } + // No octets with decimal values greater than 127 + // are allowed and neither are NULs (octets with decimal value 0). CR + //(decimal value 13) and LF (decimal value 10) octets only occur as + // part of CRLF line separation sequences. + char[] chars = str.toCharArray(); + for (int j = 0; j < chars.length; j++) + { + if((chars[j] > 127) || (chars[j] == 0) || + (chars[j] == 10) || (chars[j] == 13)) + { + throw new AssertionFailException("The char (" + chars[j] + + ")[code=" + (byte) chars[j] + " position=" + j + + "] does not allows in 7bit encoding content"); + } + } + } + } + + /** + * Validate an 8bit encoded message (RFC2045) + * @param message message to check + * @throws AssertionFailException if message does not conform + */ + private void checkOn8bit(String message) + throws AssertionFailException + { + String[] strs = split(message); + for (int i = 0; i < strs.length; i++) + { + String str = strs[i]; + + // check string length + if(str.length() > 998) + { + throw new AssertionFailException("The length (" + str.length() + + ") of the line (" + (i+1) + ") greater than 998"); + } + // octets with decimal values greater than 127 + // may be used. As with "7bit data" CR and LF octets only occur as part + // of CRLF line separation sequences and no NULs are allowed. + char[] chars = str.toCharArray(); + for (int j = 0; j < chars.length; j++) + { + if((chars[j] == 0) || (chars[j] == 10) || (chars[j] == 13)) + { + throw new AssertionFailException("The char (" + chars[j] + + ")[code=" + (byte) chars[j] + " position=" + j + + "] does not allows in 8bit encoding content"); + } + } + } + } + + /** + * Validate a quoted-printable encoded message (RFC2045) + * @param message message to check + * @throws AssertionFailException if message does not conform + */ + private void checkOnQuotedPrintable(String message) + throws AssertionFailException + { + String[] strs = split(message); + for (int i = 0; i < strs.length; i++) + { + // check length + // RFC2045 + // (5) (Soft Line Breaks) The Quoted-Printable encoding + //REQUIRES that encoded lines be no more than 76 + //characters long. If longer lines are to be encoded + //with the Quoted-Printable encoding, "soft" line breaks + //must be used. An equal sign as the last character on a + //encoded line indicates such a non-significant ("soft") + //line break in the encoded text. + if(((strs[i].indexOf("\t") != -1) || (strs[i].indexOf(" ") != -1)) && + (strs[i].length() > 76)) + { + throw new AssertionFailException("The length (" + strs[i].length() + + ") of the line (" + (i+1) + + ") greater than 76, \"soft\" line breaks must be used"); + } + + char[] chars = strs[i].toCharArray(); + for (int j = 0; j < chars.length; j++) + { + //(1) (General 8bit representation) Any octet, except a CR or + //LF that is part of a CRLF line break of the canonical + //(standard) form of the data being encoded, may be + //represented by an "=" followed by a two digit + //hexadecimal representation of the octet's value. The + //digits of the hexadecimal alphabet, for this purpose, + //are "0123456789ABCDEF". Uppercase letters must be + //used; lowercase letters are not allowed. Thus, for + //example, the decimal value 12 (US-ASCII form feed) can + //be represented by "=0C", and the decimal value 61 (US- + //ASCII EQUAL SIGN) can be represented by "=3D". This + //rule must be followed except when the following rules + //allow an alternative encoding. + // (2) (Literal representation) Octets with decimal values of + //33 through 60 inclusive, and 62 through 126, inclusive, + //MAY be represented as the US-ASCII characters which + //correspond to those octets (EXCLAMATION POINT through + //LESS THAN, and GREATER THAN through TILDE, + //respectively). + if((chars[j] == 61) && (chars.length > j+2)) + { + if(!isHex(chars[j+1]) || !isHex(chars[j+2])) + { + throw new AssertionFailException("the quoted char (" + + chars[j] + chars[j+1] + chars[j+2] + ") is incorrect"); + } else { + j += 2; + } + } + // check for space and tab + else if((chars[j] != 9) && (chars[j] != 32)) + { + // check invalid symbol + if((chars[j] == 0) || (chars[j] == 10) || (chars[j] == 13) || + (chars[j] < 33) || (chars[j] > 126) || (chars[j] == 61)) + { + throw new AssertionFailException("The char (" + chars[j] + + ")[code=" + (byte) chars[j] + " position=" + j + + "] must be quoted"); + } + } + } + } + } + + /** + * Validate a base64 encoded message (RFC3548) + * @param message message to check + * @throws AssertionFailException if message does not conform + */ + private void checkOnBase64(String message) + throws AssertionFailException + { + String[] strs = split(message); + for (int i = 0; i < strs.length; i++) + { + String str = strs[i]; + + // check string length + if(str.length() > 76) + { + throw new AssertionFailException("The length (" + str.length() + + ") of the line (" + (i+1) + ") greater than 998"); + } + // check for "ABCDEFGHIJKLMNOPQRSTUVWXYZabcefghijklmnopqrstuvwxyz0123456789/+" + char[] chars = str.toCharArray(); + for (int j = 0; j < chars.length; j++) + { + char c = chars[i]; + if((c < 47) || (c > 122) || ((c > 57) && (c < 65)) || + ((c > 90) && (c < 97))) + { + throw new AssertionFailException("The char (" + chars[j] + + ")[code=" + (byte) chars[j] + " position=" + j + + "] does not allows in base64 encoding content"); + } + } + } + } + + /** + * split string to array of strings and use as delimeter CRLF + * @param str original string + * @return array of strings + */ + private String[] split(String str) + { + ArrayList list = new ArrayList(); + for(int idx = str.indexOf("\r\n"); idx != -1; idx = str.indexOf("\r\n")) + { + list.add(str.substring(0, idx)); + str = str.substring(idx+2); + } + list.add(str); + return (String[]) list.toArray(new String[list.size()]); + } + + /** + * Returns true if byte is "0123456789ABCDEF" range, false othewise + * @param c char + * @return true if byte is "0123456789ABCDEF" range, false othewise + */ + private boolean isHex(char c) { + return (((c >= 48) && (c <= 57)) || ((c >= 65) && (c <= 70))); + } +}
\ No newline at end of file |