GUACAMOLE-1048: Support server control commands during handshake

This commit is contained in:
Tomer Gabel
2020-04-23 17:51:49 +03:00
committed by Michael Jumper
parent 6644955fff
commit fdff3e187b
2 changed files with 87 additions and 2 deletions

View File

@@ -0,0 +1,55 @@
/*
* 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.guacamole;
import org.apache.guacamole.protocol.GuacamoleStatus;
/**
* The exception thrown when the Guacamole server explicitly sends an error
* instruction to the client. The error message and status code reflect the arguments
* of the error instruction as determined by the server.
*/
public class GuacamoleServerErrorInstructionException extends GuacamoleServerException {
/**
* The Guacamole protocol status code, as determined by the server;
*/
private final GuacamoleStatus status;
/**
* Creates a new GuacamoleServerErrorInstructionException with the given
* message and status.
*
* @param message
* A human readable description of the exception that occurred.
*
* @param status
* The status code, as determined by the server from which the
* instruction originated.
*/
public GuacamoleServerErrorInstructionException(String message, GuacamoleStatus status) {
super(message);
this.status = status;
}
@Override
public GuacamoleStatus getStatus() {
return status;
}
}

View File

@@ -21,6 +21,7 @@ package org.apache.guacamole.protocol;
import java.util.List;
import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.GuacamoleServerErrorInstructionException;
import org.apache.guacamole.GuacamoleServerException;
import org.apache.guacamole.io.GuacamoleReader;
import org.apache.guacamole.io.GuacamoleWriter;
@@ -60,11 +61,34 @@ public class ConfiguredGuacamoleSocket extends DelegatingGuacamoleSocket {
private GuacamoleProtocolVersion protocolVersion =
GuacamoleProtocolVersion.VERSION_1_0_0;
/**
* Parses the arguments for the Guacamole "error" server instruction and returns
* the corresponding exception.
* @param args The arguments as provided by the server instruction.
* @return An instance of {@link GuacamoleServerErrorInstructionException} configured
* with the server-provided arguments, or a generic {@link GuacamoleServerException} if
* the specified arguments are invalid.
*/
private static GuacamoleServerException parseServerErrorInstructionArgs(List<String> args) {
try {
if (args.size() >= 2) {
int code = Integer.parseInt(args.get(1));
GuacamoleStatus status = GuacamoleStatus.fromGuacamoleStatusCode(code);
return new GuacamoleServerErrorInstructionException(args.get(0), status);
}
} catch (NumberFormatException ignored) {}
return new GuacamoleServerException("Invalid error instruction arguments received: " + args);
}
/**
* Waits for the instruction having the given opcode, returning that
* instruction once it has been read. If the instruction is never read,
* an exception is thrown.
*
* Respects server control instructions that are allowed during the handshake
* phase, namely {@code error} and {@code disconnect}.
*
* @param reader The reader to read instructions from.
* @param opcode The opcode of the instruction we are expecting.
* @return The instruction having the given opcode.
@@ -79,6 +103,12 @@ public class ConfiguredGuacamoleSocket extends DelegatingGuacamoleSocket {
if (instruction == null)
throw new GuacamoleServerException("End of stream while waiting for \"" + opcode + "\".");
// Handle server control instructions
if ("disconnect".equals(instruction.getOpcode()))
throw new GuacamoleServerException("Server disconnected while waiting for \"" + opcode + "\".");
if ("error".equals(instruction.getOpcode()))
throw parseServerErrorInstructionArgs(instruction.getArgs());
// Ensure instruction has expected opcode
if (!instruction.getOpcode().equals(opcode))
throw new GuacamoleServerException("Expected \"" + opcode + "\" instruction but instead received \"" + instruction.getOpcode() + "\".");