mirror of
				https://github.com/gyurix1968/guacamole-client.git
				synced 2025-10-30 16:43:22 +00:00 
			
		
		
		
	GUACAMOLE-615: Correct parser calculation of element lengths.
This commit is contained in:
		| @@ -93,6 +93,22 @@ public class GuacamoleInstruction { | ||||
|         return args; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Appends the given value to the provided StringBuilder as a Guacamole | ||||
|      * instruction element, including length prefix. | ||||
|      * | ||||
|      * @param buff | ||||
|      *     The StringBuilder to append the element to. | ||||
|      * | ||||
|      * @param element | ||||
|      *     The string value of the element to append. | ||||
|      */ | ||||
|     private static void appendElement(StringBuilder buff, String element) { | ||||
|         buff.append(element.codePointCount(0, element.length())); | ||||
|         buff.append('.'); | ||||
|         buff.append(element); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns this GuacamoleInstruction in the form it would be sent over the | ||||
|      * Guacamole protocol. | ||||
| @@ -111,16 +127,12 @@ public class GuacamoleInstruction { | ||||
|             StringBuilder buff = new StringBuilder(); | ||||
|  | ||||
|             // Write opcode | ||||
|             buff.append(opcode.length()); | ||||
|             buff.append('.'); | ||||
|             buff.append(opcode); | ||||
|             appendElement(buff, opcode); | ||||
|  | ||||
|             // Write argument values | ||||
|             for (String value : args) { | ||||
|                 buff.append(','); | ||||
|                 buff.append(value.length()); | ||||
|                 buff.append('.'); | ||||
|                 buff.append(value); | ||||
|                 appendElement(buff, value); | ||||
|             } | ||||
|  | ||||
|             // Write terminator | ||||
|   | ||||
| @@ -21,7 +21,6 @@ package org.apache.guacamole.protocol; | ||||
|  | ||||
| import java.util.Arrays; | ||||
| import java.util.Iterator; | ||||
| import java.util.List; | ||||
| import org.apache.guacamole.GuacamoleException; | ||||
| import org.apache.guacamole.GuacamoleServerException; | ||||
|  | ||||
| @@ -87,10 +86,18 @@ public class GuacamoleParser implements Iterator<GuacamoleInstruction> { | ||||
|     private State state = State.PARSING_LENGTH; | ||||
|  | ||||
|     /** | ||||
|      * The length of the current element, if known. | ||||
|      * The length of the current element, if known, in Java characters. This | ||||
|      * value may be adjusted as an element is parsed to take surrogates into | ||||
|      * account. | ||||
|      */ | ||||
|     private int elementLength = 0; | ||||
|  | ||||
|     /** | ||||
|      * The length of the current element, if known, in Unicode codepoints. This | ||||
|      * value will NOT change as an element is parsed. | ||||
|      */ | ||||
|     private int elementCodepoints; | ||||
|  | ||||
|     /** | ||||
|      * The number of elements currently parsed. | ||||
|      */ | ||||
| @@ -104,13 +111,22 @@ public class GuacamoleParser implements Iterator<GuacamoleInstruction> { | ||||
|     /** | ||||
|      * Appends data from the given buffer to the current instruction. | ||||
|      *  | ||||
|      * @param chunk The buffer containing the data to append. | ||||
|      * @param offset The offset within the buffer where the data begins. | ||||
|      * @param length The length of the data to append. | ||||
|      * @return The number of characters appended, or 0 if complete instructions | ||||
|      *         have already been parsed and must be read via next() before | ||||
|      *         more data can be appended. | ||||
|      * @throws GuacamoleException If an error occurs while parsing the new data. | ||||
|      * @param chunk | ||||
|      *     The buffer containing the data to append. | ||||
|      * | ||||
|      * @param offset | ||||
|      *     The offset within the buffer where the data begins. | ||||
|      * | ||||
|      * @param length | ||||
|      *     The length of the data to append. | ||||
|      * | ||||
|      * @return | ||||
|      *     The number of characters appended, or 0 if complete instructions | ||||
|      *     have already been parsed and must be read via next() before more | ||||
|      *     data can be appended. | ||||
|      * | ||||
|      * @throws GuacamoleException | ||||
|      *     If an error occurs while parsing the new data. | ||||
|      */ | ||||
|     public int append(char chunk[], int offset, int length) throws GuacamoleException { | ||||
|  | ||||
| @@ -156,39 +172,63 @@ public class GuacamoleParser implements Iterator<GuacamoleInstruction> { | ||||
|             } | ||||
|  | ||||
|             // Save length | ||||
|             elementLength = parsedLength; | ||||
|             elementCodepoints = elementLength = parsedLength; | ||||
|  | ||||
|         } // end parse length | ||||
|  | ||||
|         // Parse element content, if available | ||||
|         if (state == State.PARSING_CONTENT && charsParsed + elementLength + 1 <= length) { | ||||
|         while (state == State.PARSING_CONTENT && charsParsed + elementLength + 1 <= length) { | ||||
|  | ||||
|             // Read element | ||||
|             // Read element (which may not match element length if surrogate | ||||
|             // characters are present) | ||||
|             String element = new String(chunk, offset + charsParsed, elementLength); | ||||
|  | ||||
|             // Verify element contains the number of whole Unicode characters | ||||
|             // expected, scheduling a future read if we don't yet have enough | ||||
|             // characters | ||||
|             int codepoints = element.codePointCount(0, element.length()); | ||||
|             if (codepoints < elementCodepoints) { | ||||
|                 elementLength += elementCodepoints - codepoints; | ||||
|                 continue; | ||||
|             } | ||||
|  | ||||
|             // If the current element ends with a character involving both | ||||
|             // a high and low surrogate, elementLength points to the low | ||||
|             // surrogate and NOT the element terminator. We must correct the | ||||
|             // length and reevaluate. | ||||
|             else if (Character.isSurrogatePair(chunk[offset + charsParsed + elementLength - 1], | ||||
|                     chunk[offset + charsParsed + elementLength])) { | ||||
|                 elementLength++; | ||||
|                 continue; | ||||
|             } | ||||
|  | ||||
|             charsParsed += elementLength; | ||||
|             elementLength = 0; | ||||
|  | ||||
|             // Read terminator char following element | ||||
|             char terminator = chunk[offset + charsParsed++]; | ||||
|  | ||||
|             // Add element to currently parsed elements | ||||
|             elements[elementCount++] = element; | ||||
|              | ||||
|             // If semicolon, store end-of-instruction | ||||
|             if (terminator == ';') { | ||||
|                 state = State.COMPLETE; | ||||
|                 parsedInstruction = new GuacamoleInstruction(elements[0], | ||||
|                         Arrays.asList(elements).subList(1, elementCount)); | ||||
|             } | ||||
|  | ||||
|             // If comma, move on to next element | ||||
|             else if (terminator == ',') | ||||
|                 state = State.PARSING_LENGTH; | ||||
|             // Read terminator char following element | ||||
|             char terminator = chunk[offset + charsParsed++]; | ||||
|             switch (terminator) { | ||||
|  | ||||
|                 // If semicolon, store end-of-instruction | ||||
|                 case ';': | ||||
|                     state = State.COMPLETE; | ||||
|                     parsedInstruction = new GuacamoleInstruction(elements[0], | ||||
|                             Arrays.asList(elements).subList(1, elementCount)); | ||||
|                     break; | ||||
|  | ||||
|                 // If comma, move on to next element | ||||
|                 case ',': | ||||
|                     state = State.PARSING_LENGTH; | ||||
|                     break; | ||||
|  | ||||
|                 // Otherwise, parse error | ||||
|                 default: | ||||
|                     state = State.ERROR; | ||||
|                     throw new GuacamoleServerException("Element terminator of instruction was not ';' nor ','"); | ||||
|  | ||||
|             // Otherwise, parse error | ||||
|             else { | ||||
|                 state = State.ERROR; | ||||
|                 throw new GuacamoleServerException("Element terminator of instruction was not ';' nor ','"); | ||||
|             } | ||||
|  | ||||
|         } // end parse content | ||||
|   | ||||
		Reference in New Issue
	
	Block a user