使用Android的HTTP CONNECT方法

时间:2015-03-02 08:56:02

标签: android http proxy httpclient connect

我想扩展现有的Android应用程序,该应用程序设置与远程设备的http连接,该远程设备向其发送命令并从中接收值。

该功能包括通过已设置的自定义代理服务器的隧道连接。我给出了http标头格式,这应该使代理服务器创建并为我的应用程序提供隧道。

CONNECT <some id>.<target ip>:80 HTTP/1.1
Host: <proxy ip>:443
Authorization: basic <base64 encoded auth string>

# Here beginns the payload for the target device. It could be whatever.
GET / HTTP/1.1
Host: 127.0.0.1:80

该应用程序使用Apache HttpClient库来处理它的连接,我想与之集成。但这不是强制性的 授权是标准的基本认证。

我无法实现此功能,因为我不清楚HttpClient是如何用于此类行为的。 库中没有CONNECT方法,只有GETPOST等等。我认为这将由HttpClient实例的代理设置管理 这里的问题是请求行不是标准的,因为CONNECT行包含自定义代理随后将解析和解释的id。

我现在想知道是否有任何预期的方法使用Apache HttpClient来实现它,以及给出这个样本数据会是什么样子,或者我是否必须为此实现我自己的方法。如果是这样,那么它应该实现哪个接口(有一些接口听起来合理)。

任何解释,摘录或指针都会受到赞赏。

更新: 我现在有一个小片段设置,没有Android。只是简单的Java和Apache HttpClient。我仍然认为请求中Host不匹配是一个问题,因为我无法建立连接。

final HttpClient httpClient = new DefaultHttpClient();

// Set proxy
HttpHost proxy = new HttpHost (deviceId + "." + "proxy ip", 443, "https");
httpClient.getParams().setParameter (ConnRoutePNames.DEFAULT_PROXY, proxy);

final HttpGet httpGet = new HttpGet("http://" + "target device ip");
httpGet.addHeader ("Authorization", "Basic" + 
    Base64.encodeBase64String((username + ":" + password).getBytes()));
// Trying to overvrite the host in the header containing the device Id
httpGet.setHeader("Host", "proxy ip");

System.out.println("Sending request..");
try {
    final HttpResponse httpResponse = httpClient.execute (httpGet);
    final InputStream inputStream = httpResponse.getEntity ().getContent ();
    final InputStreamReader inputStreamReader = 
        new InputStreamReader(inputStream, "ISO-8859-1");

    final BufferedReader bufferedReader = new BufferedReader(inputStreamReader);

    final StringBuilder stringBuilder = new StringBuilder ();
    String bufferedStrChunk = null;

    while ((bufferedStrChunk = bufferedReader.readLine ()) != null) {
        stringBuilder.append (bufferedStrChunk);
    }

    System.out.println("Received String: " + stringBuilder.toString());
}
catch (final ClientProtocolException exception) {
    System.out.println("ClientProtocolException");
    exception.printStackTrace();
}
catch (final IOException exception) {
    System.out.println("IOException");
    exception.
}

这对我来说看起来相当不错,它实际上可以正常工作&#34;。 无论如何,我收到以下日志和跟踪:

Sending request..
2015/03/03 13:16:16:199 CET [DEBUG] ClientParamsStack - 'http.route.default-proxy': https://"device id"."proxy ip":443
2015/03/03 13:16:16:207 CET [DEBUG] SingleClientConnManager - Get connection for route HttpRoute[{}->https://"device id"."proxy ip":443->http://"target device ip"]
2015/03/03 13:16:16:549 CET [DEBUG] ClientParamsStack - 'http.tcp.nodelay': true
2015/03/03 13:16:16:549 CET [DEBUG] ClientParamsStack - 'http.socket.buffer-size': 8192
2015/03/03 13:16:16:563 CET [DEBUG] DefaultClientConnection - Connection shut down
2015/03/03 13:16:16:563 CET [DEBUG] SingleClientConnManager - Releasing connection org.apache.http.impl.conn.SingleClientConnManager$ConnAdapter@bc6a08
Exception in thread "main" java.lang.IllegalStateException: Unable to establish route.
planned = HttpRoute[{}->https://"device id"."proxy ip":443->http://"target device ip"]
current = HttpRoute[{s}->https://"device id"."proxy ip":443->http://"target device ip"]
    at org.apache.http.impl.client.DefaultRequestDirector.establishRoute(DefaultRequestDirector.java:672)
    at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:385)
    at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:641)
    at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:576)
    at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:554)
    at run.main(run.java:71)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:134)

任何想法出了什么问题?

更新:如上所述here,这可能是由于重定向时出现错误。目标重定向的事实告诉我,我没有达到正确的目标,这意味着Host参数可能没有被覆盖。

1 个答案:

答案 0 :(得分:0)

事实上,HttpClient根本无法做到这一点,我试错了。完成后使用TcpSocket(或SSLSocket)。自定义CONNECT标头可以简单地组装和发送:

final Socket tcpSocket = SSLSocketFactory.getDefault().createSocket("host ip", 443);
String connect = "custom CONNECT header";

tcpSocket.getOutputStream().write((connect).getBytes());
tcpSocket.getOutputStream().flush();

然后可以使用BufferedReader或其他任何内容来读取服务器的响应。