001/*
002 * $HeadURL: http://juliusdavies.ca/svn/not-yet-commons-ssl/tags/commons-ssl-0.3.15/src/java/org/apache/commons/ssl/Util.java $
003 * $Revision: 166 $
004 * $Date: 2014-04-28 11:40:25 -0700 (Mon, 28 Apr 2014) $
005 *
006 * ====================================================================
007 * Licensed to the Apache Software Foundation (ASF) under one
008 * or more contributor license agreements.  See the NOTICE file
009 * distributed with this work for additional information
010 * regarding copyright ownership.  The ASF licenses this file
011 * to you under the Apache License, Version 2.0 (the
012 * "License"); you may not use this file except in compliance
013 * with the License.  You may obtain a copy of the License at
014 *
015 *   http://www.apache.org/licenses/LICENSE-2.0
016 *
017 * Unless required by applicable law or agreed to in writing,
018 * software distributed under the License is distributed on an
019 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
020 * KIND, either express or implied.  See the License for the
021 * specific language governing permissions and limitations
022 * under the License.
023 * ====================================================================
024 *
025 * This software consists of voluntary contributions made by many
026 * individuals on behalf of the Apache Software Foundation.  For more
027 * information on the Apache Software Foundation, please see
028 * <http://www.apache.org/>.
029 *
030 */
031
032package org.apache.commons.ssl;
033
034import org.apache.commons.ssl.util.ByteArrayReadLine;
035import org.apache.commons.ssl.util.IPAddressParser;
036
037import java.io.ByteArrayInputStream;
038import java.io.IOException;
039import java.io.InputStream;
040import java.io.OutputStream;
041import java.net.InetAddress;
042import java.net.UnknownHostException;
043import java.util.LinkedList;
044import java.util.Map;
045import java.util.StringTokenizer;
046import java.util.TreeMap;
047
048/**
049 * @author Credit Union Central of British Columbia
050 * @author <a href="http://www.cucbc.com/">www.cucbc.com</a>
051 * @author <a href="mailto:juliusdavies@cucbc.com">juliusdavies@cucbc.com</a>
052 * @since 28-Feb-2006
053 */
054public class Util {
055    public final static int SIZE_KEY = 0;
056    public final static int LAST_READ_KEY = 1;
057
058    public static boolean isYes(String yesString) {
059        if (yesString == null) {
060            return false;
061        }
062        String s = yesString.trim().toUpperCase();
063        return "1".equals(s) || "YES".equals(s) || "TRUE".equals(s) ||
064               "ENABLE".equals(s) || "ENABLED".equals(s) || "Y".equals(s) ||
065               "ON".equals(s);
066    }
067
068    public static String trim(final String s) {
069        if (s == null || "".equals(s)) {
070            return s;
071        }
072        int i = 0;
073        int j = s.length() - 1;
074        while (isWhiteSpace(s.charAt(i))) {
075            i++;
076        }
077        while (isWhiteSpace(s.charAt(j))) {
078            j--;
079        }
080        return j >= i ? s.substring(i, j + 1) : "";
081    }
082
083    public static boolean isWhiteSpace(final char c) {
084        switch (c) {
085            case 0:
086            case ' ':
087            case '\t':
088            case '\n':
089            case '\r':
090            case '\f':
091                return true;
092            default:
093                return false;
094        }
095    }
096
097    public static void pipeStream(InputStream in, OutputStream out)
098        throws IOException {
099        pipeStream(in, out, true);
100    }
101
102    public static void pipeStream(InputStream in, OutputStream out,
103                                  boolean autoClose)
104        throws IOException {
105        byte[] buf = new byte[8192];
106        IOException ioe = null;
107        try {
108            int bytesRead = in.read(buf);
109            while (bytesRead >= 0) {
110                if (bytesRead > 0) {
111                    out.write(buf, 0, bytesRead);
112                }
113                bytesRead = in.read(buf);
114            }
115        }
116        finally {
117            // Probably it's best to let consumer call "close", but I'm usually
118            // the consumer, and I want to be lazy.  [Julius, November 20th, 2006]
119            try { in.close(); } catch (IOException e) { ioe = e; }
120            if (autoClose) {
121                try { out.close(); } catch (IOException e) { ioe = e; }
122            }
123        }
124        if (ioe != null) {
125            throw ioe;
126        }
127    }
128
129    public static byte[] streamToBytes(final ByteArrayInputStream in,
130                                       int maxLength) {
131        byte[] buf = new byte[maxLength];
132        int[] status = fill(buf, 0, in);
133        int size = status[SIZE_KEY];
134        if (buf.length != size) {
135            byte[] smallerBuf = new byte[size];
136            System.arraycopy(buf, 0, smallerBuf, 0, size);
137            buf = smallerBuf;
138        }
139        return buf;
140    }
141
142    public static byte[] streamToBytes(final InputStream in, int maxLength)
143        throws IOException {
144        byte[] buf = new byte[maxLength];
145        int[] status = fill(buf, 0, in);
146        int size = status[SIZE_KEY];
147        if (buf.length != size) {
148            byte[] smallerBuf = new byte[size];
149            System.arraycopy(buf, 0, smallerBuf, 0, size);
150            buf = smallerBuf;
151        }
152        return buf;
153    }
154
155    public static byte[] streamToBytes(final InputStream in) throws IOException {
156        byte[] buf = new byte[4096];
157        try {
158            int[] status = fill(buf, 0, in);
159            int size = status[SIZE_KEY];
160            int lastRead = status[LAST_READ_KEY];
161            while (lastRead != -1) {
162                buf = resizeArray(buf);
163                status = fill(buf, size, in);
164                size = status[SIZE_KEY];
165                lastRead = status[LAST_READ_KEY];
166            }
167            if (buf.length != size) {
168                byte[] smallerBuf = new byte[size];
169                System.arraycopy(buf, 0, smallerBuf, 0, size);
170                buf = smallerBuf;
171            }
172        }
173        finally {
174            in.close();
175        }
176        return buf;
177    }
178
179    public static byte[] streamToBytes(final ByteArrayInputStream in) {
180        byte[] buf = new byte[4096];
181        int[] status = fill(buf, 0, in);
182        int size = status[SIZE_KEY];
183        int lastRead = status[LAST_READ_KEY];
184        while (lastRead != -1) {
185            buf = resizeArray(buf);
186            status = fill(buf, size, in);
187            size = status[SIZE_KEY];
188            lastRead = status[LAST_READ_KEY];
189        }
190        if (buf.length != size) {
191            byte[] smallerBuf = new byte[size];
192            System.arraycopy(buf, 0, smallerBuf, 0, size);
193            buf = smallerBuf;
194        }
195        // in.close();  <-- this is a no-op on ByteArrayInputStream.
196        return buf;
197    }
198
199    public static int[] fill(final byte[] buf, final int offset,
200                             final InputStream in)
201        throws IOException {
202        int read = in.read(buf, offset, buf.length - offset);
203        int lastRead = read;
204        if (read == -1) {
205            read = 0;
206        }
207        while (lastRead != -1 && read + offset < buf.length) {
208            lastRead = in.read(buf, offset + read, buf.length - read - offset);
209            if (lastRead != -1) {
210                read += lastRead;
211            }
212        }
213        return new int[]{offset + read, lastRead};
214    }
215
216    public static int[] fill(final byte[] buf, final int offset,
217                             final ByteArrayInputStream in) {
218        int read = in.read(buf, offset, buf.length - offset);
219        int lastRead = read;
220        if (read == -1) {
221            read = 0;
222        }
223        while (lastRead != -1 && read + offset < buf.length) {
224            lastRead = in.read(buf, offset + read, buf.length - read - offset);
225            if (lastRead != -1) {
226                read += lastRead;
227            }
228        }
229        return new int[]{offset + read, lastRead};
230    }
231
232    public static byte[] resizeArray(final byte[] bytes) {
233        byte[] biggerBytes = new byte[bytes.length * 2];
234        System.arraycopy(bytes, 0, biggerBytes, 0, bytes.length);
235        return biggerBytes;
236    }
237
238    public static String pad(String s, final int length, final boolean left) {
239        if (s == null) {
240            s = "";
241        }
242        int diff = length - s.length();
243        if (diff == 0) {
244            return s;
245        } else if (diff > 0) {
246            StringBuffer sb = new StringBuffer();
247            if (left) {
248                for (int i = 0; i < diff; i++) {
249                    sb.append(' ');
250                }
251            }
252            sb.append(s);
253            if (!left) {
254                for (int i = 0; i < diff; i++) {
255                    sb.append(' ');
256                }
257            }
258            return sb.toString();
259        } else {
260            return s;
261        }
262    }
263
264    public static Map parseArgs(final String[] cargs) {
265        Map args = new TreeMap();
266        Map ARGS_MATCH = Ping.ARGS_MATCH;
267
268        int l = cargs.length;
269        final String[] EMPTY_VALUES = {""};
270        for (int i = 0; i < l; i++) {
271            String k = cargs[i];
272            Ping.Arg a = (Ping.Arg) ARGS_MATCH.get(k);
273            if (l > i + 1) {
274                String v = cargs[++i];
275                while (ARGS_MATCH.containsKey(v)) {
276                    args.put(a, EMPTY_VALUES);
277                    a = (Ping.Arg) ARGS_MATCH.get(v);
278                    v = "";
279                    if (l > i + 1) {
280                        v = cargs[++i];
281                    }
282                }
283                String[] values = new String[1];
284                values[0] = v;
285                args.put(a, values);
286                if (l > i + 1 && !ARGS_MATCH.containsKey(cargs[i + 1])) {
287                    LinkedList list = new LinkedList();
288                    list.add(v);
289                    while (l > i + 1 && !ARGS_MATCH.containsKey(cargs[i + 1])) {
290                        v = cargs[++i];
291                        list.add(v);
292                    }
293                    args.put(a, list.toArray(new String[list.size()]));
294                }
295            } else {
296                args.put(a, EMPTY_VALUES);
297            }
298        }
299        return args;
300    }
301
302    public static HostPort toAddress(final String target,
303                                     final int defaultPort)
304        throws UnknownHostException {
305        String host = target;
306        int port = defaultPort;
307        StringTokenizer st = new StringTokenizer(target, ":");
308        if (st.hasMoreTokens()) {
309            host = st.nextToken().trim();
310        }
311        if (st.hasMoreTokens()) {
312            port = Integer.parseInt(st.nextToken().trim());
313        }
314        if (st.hasMoreTokens()) {
315            throw new IllegalArgumentException("Invalid host: " + target);
316        }
317        return new HostPort(host, port);
318    }
319
320    public static String cipherToAuthType(String cipher) {
321        if (cipher == null) {
322            return null;
323        }
324
325        // SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA  ==> "DHE_DSS_EXPORT"
326        // SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA      ==> "DHE_DSS"
327        // SSL_RSA_WITH_3DES_EDE_CBC_SHA          ==> "RSA"
328
329        StringTokenizer st = new StringTokenizer(cipher.trim(), "_");
330        if (st.hasMoreTokens()) {
331            st.nextToken();  // always skip first token
332        }
333        if (st.hasMoreTokens()) {
334            String tok = st.nextToken();
335            StringBuffer buf = new StringBuffer();
336            buf.append(tok);
337            if (st.hasMoreTokens()) {
338                tok = st.nextToken();
339                while (!"WITH".equalsIgnoreCase(tok)) {
340                    buf.append('_');
341                    buf.append(tok);
342                    tok = st.nextToken();
343                }
344            }
345            return buf.toString();
346        }
347        throw new IllegalArgumentException("not a valid cipher: " + cipher);
348    }
349
350    /**
351     * Utility method to make sure IP-literals don't trigger reverse-DNS lookups.
352     */
353    public static InetAddress toInetAddress(String s) throws UnknownHostException {
354        byte[] ip = IPAddressParser.parseIPv4Literal(s);
355        if (ip == null) {
356            ip = IPAddressParser.parseIPv6Literal(s);
357        }
358        if (ip != null) {
359            // Strangely, this prevents Java's annoying SSL reverse-DNS lookup that it
360            // normally does, even with literal IP addresses.
361            return InetAddress.getByAddress(s, ip);
362        } else {
363            return InetAddress.getByName(s);
364        }
365    }
366
367    public static void main(String[] args) throws Exception {
368        String s = "line1\n\rline2\n\rline3";
369        ByteArrayInputStream in = new ByteArrayInputStream(s.getBytes());
370        ByteArrayReadLine readLine = new ByteArrayReadLine(in);
371        String line = readLine.next();
372        while (line != null) {
373            System.out.println(line);
374            line = readLine.next();
375        }
376
377        System.out.println("--------- test 2 ----------");
378
379        s = "line1\n\rline2\n\rline3\n\r\n\r";
380        in = new ByteArrayInputStream(s.getBytes());
381        readLine = new ByteArrayReadLine(in);
382        line = readLine.next();
383        while (line != null) {
384            System.out.println(line);
385            line = readLine.next();
386        }
387
388    }
389
390
391}