From a11f67fb7885f934de926bfe960ce77879b3cd8e Mon Sep 17 00:00:00 2001 From: Todd Lipcon Date: Fri, 14 Oct 2011 21:44:35 +0000 Subject: [PATCH] HADOOP-7729. Send back valid HTTP response if user hits IPC port with HTTP GET. Contributed by Todd Lipcon. git-svn-id: https://svn.apache.org/repos/asf/hadoop/common/trunk@1183512 13f79535-47bb-0310-9956-ffa450edef68 --- .../hadoop-common/CHANGES.txt | 3 ++ .../java/org/apache/hadoop/ipc/Server.java | 38 ++++++++++++++++++- .../java/org/apache/hadoop/ipc/TestIPC.java | 6 +++ 3 files changed, 45 insertions(+), 2 deletions(-) diff --git a/hadoop-common-project/hadoop-common/CHANGES.txt b/hadoop-common-project/hadoop-common/CHANGES.txt index bd3938981d..7599f15142 100644 --- a/hadoop-common-project/hadoop-common/CHANGES.txt +++ b/hadoop-common-project/hadoop-common/CHANGES.txt @@ -50,6 +50,9 @@ Trunk (unreleased changes) HADOOP-7743. Add Maven profile to create a full source tarball. (tucu) + HADOOP-7729. Send back valid HTTP response if user hits IPC port with + HTTP GET. (todd) + BUGS HADOOP-7606. Upgrade Jackson to version 1.7.1 to match the version required diff --git a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/ipc/Server.java b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/ipc/Server.java index 125ba8b2de..ddc761b5ad 100644 --- a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/ipc/Server.java +++ b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/ipc/Server.java @@ -102,6 +102,23 @@ public abstract class Server { */ public static final ByteBuffer HEADER = ByteBuffer.wrap("hrpc".getBytes()); + /** + * If the user accidentally sends an HTTP GET to an IPC port, we detect this + * and send back a nicer response. + */ + private static final ByteBuffer HTTP_GET_BYTES = ByteBuffer.wrap( + "GET ".getBytes()); + + /** + * An HTTP response to send back if we detect an HTTP request to our IPC + * port. + */ + static final String RECEIVED_HTTP_REQ_RESPONSE = + "HTTP/1.1 404 Not Found\r\n" + + "Content-type: text/plain\r\n\r\n" + + "It looks like you are making an HTTP request to a Hadoop IPC port. " + + "This is not the correct port for the web interface on this daemon.\r\n"; + // 1 : Introduce ping and server does not throw away RPCs // 3 : Introduce the protocol into the RPC connection header // 4 : Introduced SASL security layer @@ -910,6 +927,7 @@ public class Connection { private ByteArrayOutputStream authFailedResponse = new ByteArrayOutputStream(); // Fake 'call' for SASL context setup private static final int SASL_CALLID = -33; + private final Call saslCall = new Call(SASL_CALLID, null, this); private final ByteArrayOutputStream saslResponse = new ByteArrayOutputStream(); @@ -1142,7 +1160,7 @@ public int readAndProcess() throws IOException, InterruptedException { if (count < 0 || dataLengthBuffer.remaining() > 0) return count; } - + if (!rpcHeaderRead) { //Every connection is expected to send the header. if (rpcHeaderBuffer == null) { @@ -1156,7 +1174,16 @@ public int readAndProcess() throws IOException, InterruptedException { byte[] method = new byte[] {rpcHeaderBuffer.get(1)}; authMethod = AuthMethod.read(new DataInputStream( new ByteArrayInputStream(method))); - dataLengthBuffer.flip(); + dataLengthBuffer.flip(); + + // Check if it looks like the user is hitting an IPC port + // with an HTTP GET - this is a common error, so we can + // send back a simple string indicating as much. + if (HTTP_GET_BYTES.equals(dataLengthBuffer)) { + setupHttpRequestOnIpcPortResponse(); + return -1; + } + if (!HEADER.equals(dataLengthBuffer) || version != CURRENT_VERSION) { //Warning is ok since this is not supposed to happen. LOG.warn("Incorrect header or version mismatch from " + @@ -1275,6 +1302,13 @@ private void setupBadVersionResponse(int clientVersion) throws IOException { responder.doRespond(fakeCall); } } + + private void setupHttpRequestOnIpcPortResponse() throws IOException { + Call fakeCall = new Call(0, null, this); + fakeCall.setResponse(ByteBuffer.wrap( + RECEIVED_HTTP_REQ_RESPONSE.getBytes())); + responder.doRespond(fakeCall); + } /// Reads the connection header following version private void processHeader(byte[] buf) throws IOException { diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/ipc/TestIPC.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/ipc/TestIPC.java index 7c01e2f191..1515ba6216 100644 --- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/ipc/TestIPC.java +++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/ipc/TestIPC.java @@ -583,6 +583,12 @@ public void testIpcFromHadoop0_21_0() throws Exception { NetworkTraces.RESPONSE_TO_HADOOP_0_21_0_RPC); } + @Test + public void testHttpGetResponse() throws Exception { + doIpcVersionTest("GET / HTTP/1.0\r\n\r\n".getBytes(), + Server.RECEIVED_HTTP_REQ_RESPONSE.getBytes()); + } + private void doIpcVersionTest( byte[] requestData, byte[] expectedResponse) throws Exception {