You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mina.apache.org by ed...@apache.org on 2008/08/13 02:05:43 UTC

svn commit: r685389 [4/4] - in /mina/trunk/core/src/main/java/org/apache/mina/proxy: ./ event/ filter/ handlers/ handlers/http/ handlers/http/basic/ handlers/http/digest/ handlers/http/ntlm/ handlers/socks/ session/ utils/

Added: mina/trunk/core/src/main/java/org/apache/mina/proxy/utils/StringUtilities.java
URL: http://svn.apache.org/viewvc/mina/trunk/core/src/main/java/org/apache/mina/proxy/utils/StringUtilities.java?rev=685389&view=auto
==============================================================================
--- mina/trunk/core/src/main/java/org/apache/mina/proxy/utils/StringUtilities.java (added)
+++ mina/trunk/core/src/main/java/org/apache/mina/proxy/utils/StringUtilities.java Tue Aug 12 17:05:41 2008
@@ -0,0 +1,313 @@
+/*
+ *  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.mina.proxy.utils;
+
+import java.io.ByteArrayOutputStream;
+import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.security.sasl.AuthenticationException;
+import javax.security.sasl.SaslException;
+
+/**
+ * StringUtilities.java - Various methods to handle strings.
+ * Note: Some code has been borrowed from <a href="http://tedorg.free.fr/en/projects.php">Mailster </a>
+ * 
+ * @author <a href="mailto:doe_wanted@yahoo.fr">Edouard De Oliveira</a>
+ * @version $Id: $
+ */
+public class StringUtilities {
+
+    /**
+     * Returns the value of a directive from the map. If mandatory is true and the value is null,
+     * then it throws a {@link AuthenticationException}. 
+     */
+    public static String getDirectiveValue(
+            HashMap<String, String> directivesMap, String directive,
+            boolean mandatory) throws AuthenticationException {
+        String value = directivesMap.get(directive);
+        if (value == null) {
+            if (mandatory) {
+                throw new AuthenticationException("\"" + directive
+                        + "\" mandatory directive is missing");
+            } else {
+                return "";
+            }
+        }
+
+        return value;
+    }
+
+    /**
+     * Copy the directive to the {@link StringBuilder} if not null.
+     */
+    public static String copyDirective(HashMap<String, String> directives,
+            StringBuilder sb, String directive) {
+        String directiveValue = directives.get(directive);
+        if (directiveValue != null) {
+            sb.append(directive).append(" = \"").append(directiveValue).append(
+                    "\", ");
+        }
+
+        return directiveValue;
+    }
+
+    /**
+     * Copy the directive to the from src to dst if not null.
+     */
+    public static String copyDirective(HashMap<String, String> src,
+            HashMap<String, String> dst, String directive) {
+        String directiveValue = src.get(directive);
+        if (directiveValue != null) {
+            dst.put(directive, directiveValue);
+        }
+
+        return directiveValue;
+    }
+
+    /**
+     * Parses digest-challenge string, extracting each token
+     * and value(s)
+     *
+     * @param buf A non-null digest-challenge string.
+     * @throws UnsupportedEncodingException 
+     * @throws SaslException if the String cannot be parsed according to RFC 2831
+     */
+    public static HashMap<String, String> parseDirectives(byte[] buf)
+            throws SaslException {
+        HashMap<String, String> map = new HashMap<String, String>();
+        boolean gettingKey = true;
+        boolean gettingQuotedValue = false;
+        boolean expectSeparator = false;
+        byte bch;
+
+        ByteArrayOutputStream key = new ByteArrayOutputStream(10);
+        ByteArrayOutputStream value = new ByteArrayOutputStream(10);
+
+        int i = skipLws(buf, 0);
+        while (i < buf.length) {
+            bch = buf[i];
+
+            if (gettingKey) {
+                if (bch == ',') {
+                    if (key.size() != 0) {
+                        throw new SaslException("Directive key contains a ',':"
+                                + key);
+                    }
+
+                    // Empty element, skip separator and lws
+                    i = skipLws(buf, i + 1);
+                } else if (bch == '=') {
+                    if (key.size() == 0) {
+                        throw new SaslException("Empty directive key");
+                    }
+
+                    gettingKey = false; // Termination of key
+                    i = skipLws(buf, i + 1); // Skip to next non whitespace
+
+                    // Check whether value is quoted
+                    if (i < buf.length) {
+                        if (buf[i] == '"') {
+                            gettingQuotedValue = true;
+                            ++i; // Skip quote
+                        }
+                    } else {
+                        throw new SaslException("Valueless directive found: "
+                                + key.toString());
+                    }
+                } else if (isLws(bch)) {
+                    // LWS that occurs after key
+                    i = skipLws(buf, i + 1);
+
+                    // Expecting '='
+                    if (i < buf.length) {
+                        if (buf[i] != '=') {
+                            throw new SaslException("'=' expected after key: "
+                                    + key.toString());
+                        }
+                    } else {
+                        throw new SaslException("'=' expected after key: "
+                                + key.toString());
+                    }
+                } else {
+                    key.write(bch); // Append to key
+                    ++i; // Advance
+                }
+            } else if (gettingQuotedValue) {
+                // Getting a quoted value
+                if (bch == '\\') {
+                    // quoted-pair = "\" CHAR ==> CHAR
+                    ++i; // Skip escape
+                    if (i < buf.length) {
+                        value.write(buf[i]);
+                        ++i; // Advance
+                    } else {
+                        // Trailing escape in a quoted value
+                        throw new SaslException(
+                                "Unmatched quote found for directive: "
+                                        + key.toString() + " with value: "
+                                        + value.toString());
+                    }
+                } else if (bch == '"') {
+                    // closing quote
+                    ++i; // Skip closing quote
+                    gettingQuotedValue = false;
+                    expectSeparator = true;
+                } else {
+                    value.write(bch);
+                    ++i; // Advance
+                }
+            } else if (isLws(bch) || bch == ',') {
+                // Value terminated
+                extractDirective(map, key.toString(), value.toString());
+                key.reset();
+                value.reset();
+                gettingKey = true;
+                gettingQuotedValue = expectSeparator = false;
+                i = skipLws(buf, i + 1); // Skip separator and LWS
+            } else if (expectSeparator) {
+                throw new SaslException(
+                        "Expecting comma or linear whitespace after quoted string: \""
+                                + value.toString() + "\"");
+            } else {
+                value.write(bch); // Unquoted value
+                ++i; // Advance
+            }
+        }
+
+        if (gettingQuotedValue) {
+            throw new SaslException("Unmatched quote found for directive: "
+                    + key.toString() + " with value: " + value.toString());
+        }
+
+        // Get last pair
+        if (key.size() > 0) {
+            extractDirective(map, key.toString(), value.toString());
+        }
+
+        return map;
+    }
+
+    /**
+     * Processes directive/value pairs from the digest-challenge and
+     * fill out the provided map.
+     * 
+     * @param key A non-null String challenge token name.
+     * @param value A non-null String token value.
+     * @throws SaslException if either the key or the value is null or
+     * if the key already has a value. 
+     */
+    private static void extractDirective(HashMap<String, String> map,
+            String key, String value) throws SaslException {
+        if (map.get(key) != null) {
+            throw new SaslException("Peer sent more than one " + key
+                    + " directive");
+        } else {
+            map.put(key, value);
+        }
+    }
+
+    /**
+     * Is character a linear white space ?
+     * LWS            = [CRLF] 1*( SP | HT )
+     * Note that we're checking individual bytes instead of CRLF
+     * 
+     * @param b the byte to check
+     * @return <code>true</code> if it's a linear white space
+     */
+    public static boolean isLws(byte b) {
+        switch (b) {
+        case 13: // US-ASCII CR, carriage return
+        case 10: // US-ASCII LF, line feed
+        case 32: // US-ASCII SP, space
+        case 9: // US-ASCII HT, horizontal-tab
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * Skip all linear white spaces
+     */
+    private static int skipLws(byte[] buf, int start) {
+        int i;
+
+        for (i = start; i < buf.length; i++) {
+            if (!isLws(buf[i])) {
+                return i;
+            }
+        }
+
+        return i;
+    }
+
+    /**
+     * Used to convert username-value, passwd or realm to 8859_1 encoding
+     * if all chars in string are within the 8859_1 (Latin 1) encoding range.
+     * 
+     * @param str a non-null String
+     * @return a non-null String containing the 8859_1 encoded string
+     * @throws AuthenticationException 
+     */
+    public static String stringTo8859_1(String str)
+            throws UnsupportedEncodingException {
+        if (str == null) {
+            return "";
+        } else {
+            return new String(str.getBytes("UTF8"), "8859_1");
+        }
+    }
+
+    public static String getSingleValuedHeader(
+            Map<String, List<String>> headers, String key) {
+        List<String> values = headers.get(key);
+
+        if (values == null) {
+            return null;
+        } else {
+            if (values.size() > 1) {
+                throw new IllegalArgumentException("Header with key [\"" + key
+                        + "\"] isn't single valued !");
+            } else {
+                return values.get(0);
+            }
+        }
+    }
+
+    public static void addValueToHeader(Map<String, List<String>> headers,
+            String key, String value, boolean singleValued) {
+        List<String> values = headers.get(key);
+
+        if (values == null) {
+            values = new ArrayList<String>(1);
+            headers.put(key, values);
+        }
+
+        if (singleValued && values.size() == 1) {
+            values.set(0, value);
+        } else {
+            values.add(value);
+        }
+    }
+}
\ No newline at end of file

Propchange: mina/trunk/core/src/main/java/org/apache/mina/proxy/utils/StringUtilities.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: mina/trunk/core/src/main/java/org/apache/mina/proxy/utils/StringUtilities.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain



Re: svn commit: r685389 [4/4] - in /mina/trunk/core/src/main/java/org/apache/mina/proxy: ./ event/ filter/ handlers/ handlers/http/ handlers/http/basic/ handlers/http/digest/ handlers/http/ntlm/ handlers/socks/ session/ utils/

Posted by Emmanuel Lecharny <el...@gmail.com>.
Julien Vermillard wrote:
> Sorry but -1 here, the headers and authors tags are wrong and javadoc
> is not clear and not on all the parameters (copyDirective)
> and at the end of file you even have  javadoc less public methods.
>   
Choppé par les keufs ! :)

Ok, the @author tags should contains a ref to the mina dev list. It has 
been decided years ago. This is not a common Apache rule, but many 
projects do so. (And it's good not to receive mails from people using 
your code years after it has been committed :)

Julien, is there something else in the header which need to be fixed ?

(About the missing javadoc for public method, it might just have gone 
through the radar).

Thanks Julien for the review ! (And thanks Edouard for the big commit !)

-- 
--
cordialement, regards,
Emmanuel LĂ©charny
www.iktek.com
directory.apache.org



Re: svn commit: r685389 [4/4] - in /mina/trunk/core/src/main/java/org/apache/mina/proxy: ./ event/ filter/ handlers/ handlers/http/ handlers/http/basic/ handlers/http/digest/ handlers/http/ntlm/ handlers/socks/ session/ utils/

Posted by Julien Vermillard <jv...@gmail.com>.
Sorry but -1 here, the headers and authors tags are wrong and javadoc
is not clear and not on all the parameters (copyDirective)
and at the end of file you even have  javadoc less public methods.

2008/8/13  <ed...@apache.org>:
> Added: mina/trunk/core/src/main/java/org/apache/mina/proxy/utils/StringUtilities.java
> URL: http://svn.apache.org/viewvc/mina/trunk/core/src/main/java/org/apache/mina/proxy/utils/StringUtilities.java?rev=685389&view=auto
> ==============================================================================
> --- mina/trunk/core/src/main/java/org/apache/mina/proxy/utils/StringUtilities.java (added)
> +++ mina/trunk/core/src/main/java/org/apache/mina/proxy/utils/StringUtilities.java Tue Aug 12 17:05:41 2008
> @@ -0,0 +1,313 @@
> +/*
> + *  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.mina.proxy.utils;
> +
> +import java.io.ByteArrayOutputStream;
> +import java.io.UnsupportedEncodingException;
> +import java.util.ArrayList;
> +import java.util.HashMap;
> +import java.util.List;
> +import java.util.Map;
> +
> +import javax.security.sasl.AuthenticationException;
> +import javax.security.sasl.SaslException;
> +
> +/**
> + * StringUtilities.java - Various methods to handle strings.
> + * Note: Some code has been borrowed from <a href="http://tedorg.free.fr/en/projects.php">Mailster </a>
> + *
> + * @author <a href="mailto:doe_wanted@yahoo.fr">Edouard De Oliveira</a>
> + * @version $Id: $
> + */
> +public class StringUtilities {
> +
> +    /**
> +     * Returns the value of a directive from the map. If mandatory is true and the value is null,
> +     * then it throws a {@link AuthenticationException}.
> +     */
> +    public static String getDirectiveValue(
> +            HashMap<String, String> directivesMap, String directive,
> +            boolean mandatory) throws AuthenticationException {
> +        String value = directivesMap.get(directive);
> +        if (value == null) {
> +            if (mandatory) {
> +                throw new AuthenticationException("\"" + directive
> +                        + "\" mandatory directive is missing");
> +            } else {
> +                return "";
> +            }
> +        }
> +
> +        return value;
> +    }
> +
> +    /**
> +     * Copy the directive to the {@link StringBuilder} if not null.
> +     */
> +    public static String copyDirective(HashMap<String, String> directives,
> +            StringBuilder sb, String directive) {
> +        String directiveValue = directives.get(directive);
> +        if (directiveValue != null) {
> +            sb.append(directive).append(" = \"").append(directiveValue).append(
> +                    "\", ");
> +        }
> +
> +        return directiveValue;
> +    }
> +
> +    /**
> +     * Copy the directive to the from src to dst if not null.
> +     */
> +    public static String copyDirective(HashMap<String, String> src,
> +            HashMap<String, String> dst, String directive) {
> +        String directiveValue = src.get(directive);
> +        if (directiveValue != null) {
> +            dst.put(directive, directiveValue);
> +        }
> +
> +        return directiveValue;
> +    }
> +
> +    /**
> +     * Parses digest-challenge string, extracting each token
> +     * and value(s)
> +     *
> +     * @param buf A non-null digest-challenge string.
> +     * @throws UnsupportedEncodingException
> +     * @throws SaslException if the String cannot be parsed according to RFC 2831
> +     */
> +    public static HashMap<String, String> parseDirectives(byte[] buf)
> +            throws SaslException {
> +        HashMap<String, String> map = new HashMap<String, String>();
> +        boolean gettingKey = true;
> +        boolean gettingQuotedValue = false;
> +        boolean expectSeparator = false;
> +        byte bch;
> +
> +        ByteArrayOutputStream key = new ByteArrayOutputStream(10);
> +        ByteArrayOutputStream value = new ByteArrayOutputStream(10);
> +
> +        int i = skipLws(buf, 0);
> +        while (i < buf.length) {
> +            bch = buf[i];
> +
> +            if (gettingKey) {
> +                if (bch == ',') {
> +                    if (key.size() != 0) {
> +                        throw new SaslException("Directive key contains a ',':"
> +                                + key);
> +                    }
> +
> +                    // Empty element, skip separator and lws
> +                    i = skipLws(buf, i + 1);
> +                } else if (bch == '=') {
> +                    if (key.size() == 0) {
> +                        throw new SaslException("Empty directive key");
> +                    }
> +
> +                    gettingKey = false; // Termination of key
> +                    i = skipLws(buf, i + 1); // Skip to next non whitespace
> +
> +                    // Check whether value is quoted
> +                    if (i < buf.length) {
> +                        if (buf[i] == '"') {
> +                            gettingQuotedValue = true;
> +                            ++i; // Skip quote
> +                        }
> +                    } else {
> +                        throw new SaslException("Valueless directive found: "
> +                                + key.toString());
> +                    }
> +                } else if (isLws(bch)) {
> +                    // LWS that occurs after key
> +                    i = skipLws(buf, i + 1);
> +
> +                    // Expecting '='
> +                    if (i < buf.length) {
> +                        if (buf[i] != '=') {
> +                            throw new SaslException("'=' expected after key: "
> +                                    + key.toString());
> +                        }
> +                    } else {
> +                        throw new SaslException("'=' expected after key: "
> +                                + key.toString());
> +                    }
> +                } else {
> +                    key.write(bch); // Append to key
> +                    ++i; // Advance
> +                }
> +            } else if (gettingQuotedValue) {
> +                // Getting a quoted value
> +                if (bch == '\\') {
> +                    // quoted-pair = "\" CHAR ==> CHAR
> +                    ++i; // Skip escape
> +                    if (i < buf.length) {
> +                        value.write(buf[i]);
> +                        ++i; // Advance
> +                    } else {
> +                        // Trailing escape in a quoted value
> +                        throw new SaslException(
> +                                "Unmatched quote found for directive: "
> +                                        + key.toString() + " with value: "
> +                                        + value.toString());
> +                    }
> +                } else if (bch == '"') {
> +                    // closing quote
> +                    ++i; // Skip closing quote
> +                    gettingQuotedValue = false;
> +                    expectSeparator = true;
> +                } else {
> +                    value.write(bch);
> +                    ++i; // Advance
> +                }
> +            } else if (isLws(bch) || bch == ',') {
> +                // Value terminated
> +                extractDirective(map, key.toString(), value.toString());
> +                key.reset();
> +                value.reset();
> +                gettingKey = true;
> +                gettingQuotedValue = expectSeparator = false;
> +                i = skipLws(buf, i + 1); // Skip separator and LWS
> +            } else if (expectSeparator) {
> +                throw new SaslException(
> +                        "Expecting comma or linear whitespace after quoted string: \""
> +                                + value.toString() + "\"");
> +            } else {
> +                value.write(bch); // Unquoted value
> +                ++i; // Advance
> +            }
> +        }
> +
> +        if (gettingQuotedValue) {
> +            throw new SaslException("Unmatched quote found for directive: "
> +                    + key.toString() + " with value: " + value.toString());
> +        }
> +
> +        // Get last pair
> +        if (key.size() > 0) {
> +            extractDirective(map, key.toString(), value.toString());
> +        }
> +
> +        return map;
> +    }
> +
> +    /**
> +     * Processes directive/value pairs from the digest-challenge and
> +     * fill out the provided map.
> +     *
> +     * @param key A non-null String challenge token name.
> +     * @param value A non-null String token value.
> +     * @throws SaslException if either the key or the value is null or
> +     * if the key already has a value.
> +     */
> +    private static void extractDirective(HashMap<String, String> map,
> +            String key, String value) throws SaslException {
> +        if (map.get(key) != null) {
> +            throw new SaslException("Peer sent more than one " + key
> +                    + " directive");
> +        } else {
> +            map.put(key, value);
> +        }
> +    }
> +
> +    /**
> +     * Is character a linear white space ?
> +     * LWS            = [CRLF] 1*( SP | HT )
> +     * Note that we're checking individual bytes instead of CRLF
> +     *
> +     * @param b the byte to check
> +     * @return <code>true</code> if it's a linear white space
> +     */
> +    public static boolean isLws(byte b) {
> +        switch (b) {
> +        case 13: // US-ASCII CR, carriage return
> +        case 10: // US-ASCII LF, line feed
> +        case 32: // US-ASCII SP, space
> +        case 9: // US-ASCII HT, horizontal-tab
> +            return true;
> +        }
> +
> +        return false;
> +    }
> +
> +    /**
> +     * Skip all linear white spaces
> +     */
> +    private static int skipLws(byte[] buf, int start) {
> +        int i;
> +
> +        for (i = start; i < buf.length; i++) {
> +            if (!isLws(buf[i])) {
> +                return i;
> +            }
> +        }
> +
> +        return i;
> +    }
> +
> +    /**
> +     * Used to convert username-value, passwd or realm to 8859_1 encoding
> +     * if all chars in string are within the 8859_1 (Latin 1) encoding range.
> +     *
> +     * @param str a non-null String
> +     * @return a non-null String containing the 8859_1 encoded string
> +     * @throws AuthenticationException
> +     */
> +    public static String stringTo8859_1(String str)
> +            throws UnsupportedEncodingException {
> +        if (str == null) {
> +            return "";
> +        } else {
> +            return new String(str.getBytes("UTF8"), "8859_1");
> +        }
> +    }
> +
> +    public static String getSingleValuedHeader(
> +            Map<String, List<String>> headers, String key) {
> +        List<String> values = headers.get(key);
> +
> +        if (values == null) {
> +            return null;
> +        } else {
> +            if (values.size() > 1) {
> +                throw new IllegalArgumentException("Header with key [\"" + key
> +                        + "\"] isn't single valued !");
> +            } else {
> +                return values.get(0);
> +            }
> +        }
> +    }
> +
> +    public static void addValueToHeader(Map<String, List<String>> headers,
> +            String key, String value, boolean singleValued) {
> +        List<String> values = headers.get(key);
> +
> +        if (values == null) {
> +            values = new ArrayList<String>(1);
> +            headers.put(key, values);
> +        }
> +
> +        if (singleValued && values.size() == 1) {
> +            values.set(0, value);
> +        } else {
> +            values.add(value);
> +        }
> +    }
> +}
> \ No newline at end of file
>
> Propchange: mina/trunk/core/src/main/java/org/apache/mina/proxy/utils/StringUtilities.java
> ------------------------------------------------------------------------------
>    svn:eol-style = native
>
> Propchange: mina/trunk/core/src/main/java/org/apache/mina/proxy/utils/StringUtilities.java
> ------------------------------------------------------------------------------
>    svn:mime-type = text/plain
>
>
>