/
HttpProxyHandler.java
177 lines (156 loc) · 6.6 KB
/
HttpProxyHandler.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
package com.shinemo.mpush.core.handler;
import com.google.common.base.Strings;
import com.shinemo.mpush.api.connection.Connection;
import com.shinemo.mpush.api.protocol.Packet;
import com.shinemo.mpush.common.DnsMapping;
import com.shinemo.mpush.common.handler.BaseMessageHandler;
import com.shinemo.mpush.common.message.HttpRequestMessage;
import com.shinemo.mpush.common.message.HttpResponseMessage;
import com.shinemo.mpush.netty.client.HttpCallback;
import com.shinemo.mpush.netty.client.NettyHttpClient;
import com.shinemo.mpush.netty.client.RequestInfo;
import com.shinemo.mpush.tools.MPushUtil;
import io.netty.buffer.ByteBuf;
import io.netty.handler.codec.http.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.net.InetSocketAddress;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Map;
import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1;
/**
* Created by ohun on 2016/2/15.
*/
public class HttpProxyHandler extends BaseMessageHandler<HttpRequestMessage> {
private static final Logger LOGGER = LoggerFactory.getLogger(HttpProxyHandler.class);
private final NettyHttpClient httpClient;
private final DnsMapping dnsMapping;
public HttpProxyHandler() {
this.httpClient = new NettyHttpClient();
this.dnsMapping = new DnsMapping();
}
@Override
public HttpRequestMessage decode(Packet packet, Connection connection) {
return new HttpRequestMessage(packet, connection);
}
@Override
public void handle(HttpRequestMessage message) {
String method = message.getMethod();
String uri = message.uri;
if (Strings.isNullOrEmpty(uri)) {
HttpResponseMessage
.from(message)
.setStatusCode(400)
.setReasonPhrase("Bad Request")
.sendRaw();
LOGGER.warn("request url is empty!");
}
uri = doDnsMapping(uri);
FullHttpRequest request = new DefaultFullHttpRequest(HTTP_1_1, HttpMethod.valueOf(method), uri);
setHeaders(request, message);
setBody(request, message);
try {
httpClient.request(new RequestInfo(request, new DefaultHttpCallback(message)));
} catch (Exception e) {
HttpResponseMessage
.from(message)
.setStatusCode(500)
.setReasonPhrase("Internal Server Error")
.sendRaw();
LOGGER.error("send request ex, message=" + message, e);
}
}
private static class DefaultHttpCallback implements HttpCallback {
private final HttpRequestMessage request;
private int redirectCount;
private DefaultHttpCallback(HttpRequestMessage request) {
this.request = request;
}
@Override
public void onResponse(HttpResponse httpResponse) {
HttpResponseMessage response = HttpResponseMessage
.from(request)
.setStatusCode(httpResponse.status().code())
.setReasonPhrase(httpResponse.status().reasonPhrase().toString());
for (Map.Entry<CharSequence, CharSequence> entry : httpResponse.headers()) {
response.addHeader(entry.getKey().toString(), entry.getValue().toString());
}
if (httpResponse instanceof FullHttpResponse) {
ByteBuf body = ((FullHttpResponse) httpResponse).content();
if (body != null && body.readableBytes() > 0) {
byte[] buffer = new byte[body.readableBytes()];
body.readBytes(buffer);
response.body = buffer;
response.addHeader(HttpHeaderNames.CONTENT_LENGTH.toString(),
Integer.toString(response.body.length));
}
}
response.send();
LOGGER.debug("callback success request={}, response={}", request, response);
}
@Override
public void onFailure(int statusCode, String reasonPhrase) {
HttpResponseMessage
.from(request)
.setStatusCode(statusCode)
.setReasonPhrase(reasonPhrase)
.sendRaw();
LOGGER.warn("callback failure request={}, response={}", request, statusCode + ":" + reasonPhrase);
}
@Override
public void onException(Throwable throwable) {
HttpResponseMessage
.from(request)
.setStatusCode(500)
.setReasonPhrase("Internal Server Error")
.sendRaw();
LOGGER.error("callback exception request={}, response={}", request, 500, throwable);
}
@Override
public void onTimeout() {
HttpResponseMessage
.from(request)
.setStatusCode(408)
.setReasonPhrase("Request Timeout")
.sendRaw();
LOGGER.warn("callback timeout request={}, response={}", request, 408);
}
@Override
public boolean onRedirect(HttpResponse response) {
return redirectCount++ < 5;
}
}
private void setHeaders(FullHttpRequest request, HttpRequestMessage message) {
Map<String, String> headers = message.headers;
if (headers != null) {
HttpHeaders httpHeaders = request.headers();
for (Map.Entry<String, String> entry : headers.entrySet()) {
httpHeaders.add(entry.getKey(), entry.getValue());
}
}
InetSocketAddress remoteAddress = (InetSocketAddress) message.getConnection().getChannel().remoteAddress();
request.headers().add("x-forwarded-for", remoteAddress.getHostName() + "," + MPushUtil.getLocalIp());
request.headers().add("x-forwarded-port", Integer.toString(remoteAddress.getPort()));
}
private void setBody(FullHttpRequest request, HttpRequestMessage message) {
byte[] body = message.body;
if (body != null && body.length > 0) {
request.content().writeBytes(body);
request.headers().add(HttpHeaderNames.CONTENT_LENGTH,
Integer.toString(body.length));
}
}
private String doDnsMapping(String url) {
URI uri = null;
try {
uri = new URI(url);
} catch (URISyntaxException e) {
}
if (uri == null) return url;
String host = uri.getHost();
String localHost = dnsMapping.translate(host);
if (localHost == null) return url;
return url.replace(host, localHost);
}
}