简体   繁体   中英

HTTP CONNECT Tunnel reply with BAD Request (400)

I have this code for HTTP Tunnel

private static void doTunnelHandshake(Socket conn, String proxyHost, int proxyPort, String host, int port) throws IOException {

    String msg = "CONNECT " + host + ":" + port + " HTTP/1.1\n" + "Host: https://" + proxyHost + ":" + proxyPort + "\r\n" + "User-Agent: " + sun.net.www.protocol.http.HttpURLConnection.userAgent+ "\r\n\r\n";

OutputStream out = conn.getOutputStream();

byte b[];
try {
    /*
     * We really do want ASCII7 -- the http protocol doesn't change with
     * locale.
     */
    b = msg.getBytes("ASCII7");
} catch (UnsupportedEncodingException ignored) {
    /*
     * If ASCII7 isn't there, something serious is wrong, but Paranoia
     * Is Good (tm)
     */
    b = msg.getBytes();
}

out.write(b);
out.flush();

/*
 * We need to store the reply so we can create a detailed error message
 * to the user.
 */
byte reply[] = new byte[200];
int replyLen = 0;
int newlinesSeen = 0;
boolean headerDone = false; /* Done on first newline */

InputStream in = conn.getInputStream();

while (newlinesSeen < 2) {
    int i = in.read();
    if (i < 0) {
        throw new IOException("Unexpected EOF from proxy");
    }
    if (i == '\n') {
        headerDone = true;
        ++newlinesSeen;
    } else if (i != '\r') {
        newlinesSeen = 0;
        if (!headerDone && replyLen < reply.length) {
            reply[replyLen++] = (byte) i;
        }
    }
}

/*
 * Converting the byte array to a string is slightly wasteful in the
 * case where the connection was successful, but it's insignificant
 * compared to the network overhead.
 */
String replyStr;
try {
    replyStr = new String(reply, 0, replyLen, "ASCII7");
} catch (UnsupportedEncodingException ignored) {
    replyStr = new String(reply, 0, replyLen);
}



/* We asked for HTTP/1.0, so we should get that back */
if (!replyStr.startsWith("HTTP/1.0 200")) {
    throw new IOException("Unable to tunnel for " + host + ":" + port + ".  TunnelProxy returns \"" + replyStr + "\"");
} 

/* tunneling Handshake was successful! */
}

but apache replies

"HTTP/1.1 400 Bad Request"

Solution found!

Missing a \\r

String msg = "CONNECT " + host + ":" + port + " HTTP/1.1\r\n" + "Host: https://" + proxyHost + ":" + proxyPort + "\r\n" + "User-Agent: " + sun.net.www.protocol.http.HttpURLConnection.userAgent+ "\r\n\r\n";

Here's a theory: Your CONNECT call is malformed in that the Host header is overspecified; it is - in this case - supposed to contain not a fully qualified URL but a hostname and (if necessary) a port. the CONNECT and Host should also match. The proxy host and port are irrelevant in this case, as you already opened the socket. Your innitial request should (according to RFC 7231, sec. 4.3.6 look like this:

CONNECT host:port HTTP/1.1
Host: host:port

On a related note, you can strip the ASCII7-stuff. The "control codes" for HTTP may work in US-ASCII, but message bodies may not. Even worse, select headers may contain UTF8. I'm also a bit puzzled as you are sending out a request in HTTP/1.1 while expecting HTTP/1.0 in response in your code.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM