Coverage Report - org.mockftpserver.core.util.PortParser
 
Classes in this File Line Coverage Branch Coverage Complexity
PortParser
91%
42/46
100%
16/16
3.5
 
 1  
 /*
 2  
  * Copyright 2008 the original author or authors.
 3  
  * 
 4  
  * Licensed under the Apache License, Version 2.0 (the "License");
 5  
  * you may not use this file except in compliance with the License.
 6  
  * You may obtain a copy of the License at
 7  
  * 
 8  
  *      http://www.apache.org/licenses/LICENSE-2.0
 9  
  * 
 10  
  * Unless required by applicable law or agreed to in writing, software
 11  
  * distributed under the License is distributed on an "AS IS" BASIS,
 12  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13  
  * See the License for the specific language governing permissions and
 14  
  * limitations under the License.
 15  
  */
 16  
 package org.mockftpserver.core.util;
 17  
 
 18  
 import org.mockftpserver.core.CommandSyntaxException;
 19  
 import org.mockftpserver.core.MockFtpServerException;
 20  
 
 21  
 import java.net.InetAddress;
 22  
 import java.net.UnknownHostException;
 23  
 import java.util.Arrays;
 24  
 import java.util.List;
 25  
 
 26  
 /**
 27  
  * Utility class for parsing host and port values from command arguments.
 28  
  *
 29  
  * @author Chris Mair
 30  
  * @version $Revision: 232 $ - $Date: 2009-06-13 19:18:01 -0400 (Sat, 13 Jun 2009) $
 31  
  */
 32  
 public final class PortParser {
 33  
 
 34  
     /**
 35  
      * Parse the host address and port number of an extended address. This encoded format is used by
 36  
      * the EPRT FTP command, and supports IPv6.
 37  
      * <p/>
 38  
      * The client network address can be in IPv4 format (e.g., "132.235.1.2") or
 39  
      * IPv6 format (e.g., "1080::8:800:200C:417A"). See RFC2428 for more information.
 40  
      *
 41  
      * @param parameter - the single parameter String containing the encoded host and port number
 42  
      * @return the populated HostAndPort object
 43  
      */
 44  
     public static HostAndPort parseExtendedAddressHostAndPort(String parameter) {
 45  16
         if (parameter == null || parameter.length() == 0) {
 46  2
             throw new CommandSyntaxException("The parameter string must not be empty or null");
 47  
         }
 48  
 
 49  14
         String delimiter = parameter.substring(0,1);
 50  14
         String[] tokens = parameter.split("\\" + delimiter);
 51  
 
 52  14
         if (tokens.length < 4) {
 53  4
             throw new CommandSyntaxException("Error parsing host and port number [" + parameter + "]");
 54  
         }
 55  
 
 56  10
         int port = Integer.parseInt(tokens[3]);
 57  
 
 58  
         InetAddress host;
 59  
         try {
 60  10
             host = InetAddress.getByName(tokens[2]);
 61  
         }
 62  2
         catch (UnknownHostException e) {
 63  2
             throw new CommandSyntaxException("Error parsing host [" + tokens[2] + "]", e);
 64  8
         }
 65  
 
 66  8
         return new HostAndPort(host, port);
 67  
     }
 68  
 
 69  
     /**
 70  
      * Parse a 32-bit IP address and 16-bit port number from the String[] of FTP command parameters.
 71  
      * This is used by the FTP "PORT" command.
 72  
      *
 73  
      * @param parameters - the String[] of command parameters. It is the concatenation
 74  
      *                   of a 32-bit internet host address and a 16-bit TCP port address. This address
 75  
      *                   information is broken into 8-bit fields and the value of each field is encoded
 76  
      *                   as a separate parameter whose value is a decimal number (in character string
 77  
      *                   representation).  Thus, the six parameters for the port command would be:
 78  
      *                   h1,h2,h3,h4,p1,p2
 79  
      *                   where h1 is the high order 8 bits of the internet host address, and p1 is the
 80  
      *                   high order 8 bits of the port number.
 81  
      * @return the HostAndPort object with the host InetAddres and int port parsed from the parameters
 82  
      * @throws org.mockftpserver.core.util.AssertFailedException
 83  
      *                               - if parameters is null or contains an insufficient number of elements
 84  
      * @throws NumberFormatException - if one of the parameters does not contain a parsable integer
 85  
      */
 86  
     public static HostAndPort parseHostAndPort(String[] parameters) {
 87  33
         verifySufficientParameters(parameters);
 88  
 
 89  29
         byte host1 = parseByte(parameters[0]);
 90  29
         byte host2 = parseByte(parameters[1]);
 91  29
         byte host3 = parseByte(parameters[2]);
 92  29
         byte host4 = parseByte(parameters[3]);
 93  
 
 94  29
         byte[] address = {host1, host2, host3, host4};
 95  29
         InetAddress inetAddress = null;
 96  
         try {
 97  29
             inetAddress = InetAddress.getByAddress(address);
 98  
         }
 99  0
         catch (UnknownHostException e) {
 100  0
             throw new MockFtpServerException("Error parsing host", e);
 101  29
         }
 102  
 
 103  29
         int port1 = Integer.parseInt(parameters[4]);
 104  29
         int port2 = Integer.parseInt(parameters[5]);
 105  29
         int port = (port1 << 8) + port2;
 106  
 
 107  29
         return new HostAndPort(inetAddress, port);
 108  
     }
 109  
 
 110  
     /**
 111  
      * Convert the InetAddess and port number to a comma-delimited list of byte values,
 112  
      * suitable for the response String from the PASV command.
 113  
      *
 114  
      * @param host - the InetAddress
 115  
      * @param port - the port number
 116  
      * @return the comma-delimited list of byte values, e.g., "196,168,44,55,23,77"
 117  
      */
 118  
     public static String convertHostAndPortToCommaDelimitedBytes(InetAddress host, int port) {
 119  5
         StringBuffer buffer = new StringBuffer();
 120  5
         byte[] address = host.getAddress();
 121  25
         for (int i = 0; i < address.length; i++) {
 122  20
             int positiveValue = (address[i] >= 0) ? address[i] : 256 + address[i];
 123  20
             buffer.append(positiveValue);
 124  20
             buffer.append(",");
 125  
         }
 126  5
         int p1 = port >> 8;
 127  5
         int p2 = port % 256;
 128  5
         buffer.append(String.valueOf(p1));
 129  5
         buffer.append(",");
 130  5
         buffer.append(String.valueOf(p2));
 131  5
         return buffer.toString();
 132  
     }
 133  
 
 134  
     /**
 135  
      * Verify that the parameters is not null and contains the required number of elements
 136  
      *
 137  
      * @param parameters - the String[] of command parameters
 138  
      * @throws CommandSyntaxException - if parameters is null or contains an insufficient number of elements
 139  
      */
 140  
     private static void verifySufficientParameters(String[] parameters) {
 141  33
         if (parameters == null || parameters.length < 6) {
 142  4
             List parms = parameters == null ? null : Arrays.asList(parameters);
 143  4
             throw new CommandSyntaxException("The PORT command must contain least be 6 parameters: " + parms);
 144  
         }
 145  29
     }
 146  
 
 147  
     /**
 148  
      * Parse the specified String as an unsigned decimal byte value (i.e., 0..255). We can't just use
 149  
      * Byte.parseByte(string) because that parses the string as a signed byte.
 150  
      *
 151  
      * @param string - the String containing the decimal byte representation to be parsed
 152  
      * @return the byte value
 153  
      */
 154  
     private static byte parseByte(String string) {
 155  116
         return (byte) (0xFF & Short.parseShort(string));
 156  
     }
 157  
 
 158  
     /**
 159  
      * Private constructor. All methods are static.
 160  
      */
 161  0
     private PortParser() {
 162  0
     }
 163  
 
 164  
 }