I'm implementing a proxy server, which works locally in android app and redirects all http calls from application webView to some secure server, which return responses back as if it were initial web resource. Responses should be returned back to webView for parsing and processing. Calls redirection was enabled for webView through reflection. I'm using LittleProxy for proxy purposes, and I guess the best place to intercept all requests will be HttpFiltersSourceAdapter
, method proxyToServerRequest
. So, I've implemented proxy like this:
private void startHttpServer() {
HttpProxyServerBootstrap serverBootstrap = DefaultHttpProxyServer.bootstrap().
withManInTheMiddle(new ProxyMitmManager()).
withAddress(new InetSocketAddress("localhost", port)).
withFiltersSource(new HttpFiltersSourceAdapter() {
@Override
public HttpFilters filterRequest(HttpRequest originalRequest) {
return new HttpFiltersAdapter(originalRequest) {
@Override
public HttpResponse clientToProxyRequest(HttpObject httpObject) {
return super.clientToProxyRequest(httpObject);
}
@Override
public HttpResponse proxyToServerRequest(HttpObject httpObject) {
Log.d(LOG_TAG, "HttpObject type: " + httpObject.getClass().getName());
DefaultHttpRequest req = (DefaultHttpRequest) httpObject;
StringBuilder requestBuilder = new StringBuilder();
requestBuilder.append(this.originalRequest.getMethod().name()).append(" ");
requestBuilder.append(this.originalRequest.getUri()).append(" ");
requestBuilder.append(this.originalRequest.getProtocolVersion().text());
List<Map.Entry<String, String>> headers = req.headers().entries();
Map<String, String> headersMap = new HashMap<>();
for (Map.Entry entry : headers) {
headersMap.put((String) entry.getKey(), (String) entry.getValue());
}
try {
// here I send data to my secure server and get response
my.app.package.HttpResponse httpResponse = sendRequest(requestBuilder.toString(), headersMap);
HttpResponse nettyResponse = new DefaultFullHttpResponse(
new HttpVersion(httpResponse.getHttpVersion(), true),
new HttpResponseStatus(httpResponse.getStatusCode(), httpResponse.getStatusMessage()),
Unpooled.copiedBuffer(httpResponse.getBody()));
return nettyResponse;
} catch (Exception e) {
Errors.log(e);
}
return null;
}
@Override
public HttpObject serverToProxyResponse(HttpObject httpObject) {
return super.serverToProxyResponse(httpObject);
}
@Override
public HttpObject proxyToClientResponse(HttpObject httpObject) {
HttpObject object = httpObject;
return super.proxyToClientResponse(httpObject);
}
};
}
});
httpServer = serverBootstrap.start();
}
The problem is the following - when i start to load data, couple of requests goes OK, but then in Logcat I see this:
D: 16:20:59.601 [LittleProxy-ClientToProxyWorker-0] DEBUG o.l.p.impl.ClientToProxyConnection - (AWAITING_INITIAL) [id: 0x52573ac7, /127.0.0.1:56972 => /127.0.0.1:48654]: Writability changed. Is writable: false
D: 16:20:59.601 [LittleProxy-ClientToProxyWorker-0] DEBUG o.l.p.impl.ClientToProxyConnection - (AWAITING_INITIAL) [id: 0x52573ac7, /127.0.0.1:56972 => /127.0.0.1:48654]: Became saturated
D: 16:20:59.601 [LittleProxy-ClientToProxyWorker-0] DEBUG o.l.p.impl.ProxyToServerConnection - (DISCONNECTED): Stopped reading
E: 16:20:59.609 [LittleProxy-ClientToProxyWorker-0] ERROR o.l.p.impl.ClientToProxyConnection - (AWAITING_INITIAL) [id: 0x52573ac7, /127.0.0.1:56972 => /127.0.0.1:48654]: Caught an exception on ClientToProxyConnection
java.lang.NullPointerException: Attempt to invoke interface method 'io.netty.channel.ChannelConfig io.netty.channel.Channel.config()' on a null object reference
at org.littleshoot.proxy.impl.ProxyConnection.stopReading(ProxyConnection.java:544) ~[na:0.0]
at org.littleshoot.proxy.impl.ClientToProxyConnection.becameSaturated(ClientToProxyConnection.java:663) ~[na:0.0]
at org.littleshoot.proxy.impl.ProxyConnection.channelWritabilityChanged(ProxyConnection.java:627) ~[na:0.0]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelWritabilityChanged(AbstractChannelHandlerContext.java:391) ~[na:0.0]
at io.netty.channel.AbstractChannelHandlerContext.fireChannelWritabilityChanged(AbstractChannelHandlerContext.java:373) ~[na:0.0]
at io.netty.channel.ChannelInboundHandlerAdapter.channelWritabilityChanged(ChannelInboundHandlerAdapter.java:119) ~[na:0.0]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelWritabilityChanged(AbstractChannelHandlerContext.java:391) ~[na:0.0]
at io.netty.channel.AbstractChannelHandlerContext.fireChannelWritabilityChanged(AbstractChannelHandlerContext.java:373) ~[na:0.0]
at io.netty.channel.ChannelInboundHandlerAdapter.channelWritabilityChanged(ChannelInboundHandlerAdapter.java:119) ~[na:0.0]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelWritabilityChanged(AbstractChannelHandlerContext.java:391) ~[na:0.0]
at io.netty.channel.AbstractChannelHandlerContext.fireChannelWritabilityChanged(AbstractChannelHandlerContext.java:373) ~[na:0.0]
at io.netty.channel.ChannelInboundHandlerAdapter.channelWritabilityChanged(ChannelInboundHandlerAdapter.java:119) ~[na:0.0]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelWritabilityChanged(AbstractChannelHandlerContext.java:391) ~[na:0.0]
at io.netty.channel.AbstractChannelHandlerContext.fireChannelWritabilityChanged(AbstractChannelHandlerContext.java:373) ~[na:0.0]
at io.netty.channel.ChannelInboundHandlerAdapter.channelWritabilityChanged(ChannelInboundHandlerAdapter.java:119) ~[na:0.0]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelWritabilityChanged(AbstractChannelHandlerContext.java:391) ~[na:0.0]
at io.netty.channel.AbstractChannelHandlerContext.fireChannelWritabilityChanged(AbstractChannelHandlerContext.java:373) ~[na:0.0]
at io.netty.channel.DefaultChannelPipeline.fireChannelWritabilityChanged(DefaultChannelPipeline.java:802) ~[na:0.0]
at io.netty.channel.ChannelOutboundBuffer.incrementPendingOutboundBytes(ChannelOutboundBuffer.java:166) ~[na:0.0]
at io.netty.channel.ChannelOutboundBuffer.addMessage(ChannelOutboundBuffer.java:121) ~[na:0.0]
at io.netty.channel.AbstractChannel$AbstractUnsafe.write(AbstractChannel.java:665) ~[na:0.0]
at io.netty.channel.DefaultChannelPipeline$HeadContext.write(DefaultChannelPipeline.java:1054) ~[na:0.0]
at io.netty.channel.AbstractChannelHandlerContext.invokeWrite(AbstractChannelHandlerContext.java:658) ~[na:0.0]
at io.netty.channel.AbstractChannelHandlerContext.write(AbstractChannelHandlerContext.java:716) ~[na:0.0]
at io.netty.channel.AbstractChannelHandlerContext.write(AbstractChannelHandlerContext.java:651) ~[na:0.0]
at io.netty.channel.ChannelOutboundHandlerAdapter.write(ChannelOutboundHandlerAdapter.java:104) ~[na:0.0]
at org.littleshoot.proxy.impl.ProxyConnection$BytesWrittenMonitor.write(ProxyConnection.java:754) ~[na:0.0]
at io.netty.channel.AbstractChannelHandlerContext.invokeWrite(AbstractChannelHandlerContext.java:658) ~[na:0.0]
at io.netty.channel.AbstractChannelHandlerContext.write(AbstractChannelHandlerContext.java:716) ~[na:0.0]
at io.netty.channel.AbstractChannelHandlerContext.write(AbstractChannelHandlerContext.java:651) ~[na:0.0]
at io.netty.handler.codec.MessageToMessageEncoder.write(MessageToMessageEncoder.java:127) ~[na:0.0]
at io.net
So, my content is not visible in webView, and there are 504 Bad gateway
errors in logs appeared.
If I remove http calls to my server, everything works fine. Does anybody have ideas about it? Maybe I shouldn't send http requests to my server in proxyToServerRequest
method? If so, where exactly I should do this?