Coverage Summary for Class: JsonRpcWeb3FilterHandler (co.rsk.rpc.netty)
Class |
Class, %
|
Method, %
|
Line, %
|
JsonRpcWeb3FilterHandler |
0%
(0/1)
|
0%
(0/6)
|
0%
(0/55)
|
1 package co.rsk.rpc.netty;
2
3 import co.rsk.rpc.OriginValidator;
4 import io.netty.channel.ChannelFutureListener;
5 import io.netty.channel.ChannelHandler;
6 import io.netty.channel.ChannelHandlerContext;
7 import io.netty.channel.SimpleChannelInboundHandler;
8 import io.netty.handler.codec.http.*;
9 import org.ethereum.rpc.HttpUtils;
10 import org.slf4j.Logger;
11 import org.slf4j.LoggerFactory;
12
13 import java.net.*;
14 import java.util.ArrayList;
15 import java.util.List;
16
17 /**
18 * Created by ajlopez on 18/10/2017.
19 */
20
21 @ChannelHandler.Sharable
22 public class JsonRpcWeb3FilterHandler extends SimpleChannelInboundHandler<FullHttpRequest> {
23 private static final Logger logger = LoggerFactory.getLogger("jsonrpc");
24 private final List<String> rpcHost;
25 private final InetAddress rpcAddress;
26 private final List<String> acceptedHosts;
27
28 private OriginValidator originValidator;
29
30 public JsonRpcWeb3FilterHandler(String corsDomains, InetAddress rpcAddress, List<String> rpcHost) {
31 this.originValidator = new OriginValidator(corsDomains);
32 this.rpcHost = rpcHost;
33 this.rpcAddress = rpcAddress;
34 this.acceptedHosts = getAcceptedHosts();
35 }
36
37 private List<String> getAcceptedHosts() {
38 List<String> hosts = new ArrayList<>();
39 if (isAcceptedAddress(rpcAddress)) {
40 hosts.add(rpcAddress.getHostName());
41 hosts.add(rpcAddress.getHostAddress());
42 } else {
43 for (String host : rpcHost) {
44 try {
45 InetAddress hostAddress = InetAddress.getByName(host);
46 if (!hostAddress.isAnyLocalAddress()) {
47 hosts.add(hostAddress.getHostAddress());
48 hosts.add(hostAddress.getHostName());
49 } else {
50 logger.warn("Wildcard address is not allowed on rpc host property {}", hostAddress);
51 }
52 } catch (UnknownHostException e) {
53 logger.warn("Invalid Host defined on rpc.host", e);
54 }
55 }
56 }
57 return hosts;
58 }
59
60 @Override
61 protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest request) throws Exception {
62 HttpResponse response;
63 HttpMethod httpMethod = request.getMethod();
64 HttpHeaders headers = request.headers();
65
66 // when a request has multiple host fields declared it would be equivalent to a comma separated list
67 // the request will be inmediately rejected since it won't be parsed as a valid URI
68 // and won't work to match an item on rpc.host
69 String hostHeader = headers.get(HttpHeaders.Names.HOST);
70 String parsedHeader = parseHostHeader(hostHeader);
71
72 if (!acceptedHosts.contains(parsedHeader)) {
73 logger.debug("Invalid header HOST {}", hostHeader);
74 response = new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.BAD_REQUEST);
75 ctx.write(response).addListener(ChannelFutureListener.CLOSE);
76 return;
77 }
78
79 if (HttpMethod.POST.equals(httpMethod)) {
80
81 String mimeType = HttpUtils.getMimeType(headers.get(HttpHeaders.Names.CONTENT_TYPE));
82 String origin = headers.get(HttpHeaders.Names.ORIGIN);
83 String referer = headers.get(HttpHeaders.Names.REFERER);
84
85 if (!"application/json".equals(mimeType) && !"application/json-rpc".equals(mimeType)) {
86 logger.debug("Unsupported content type");
87 response = new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.UNSUPPORTED_MEDIA_TYPE);
88 } else if (origin != null && !this.originValidator.isValidOrigin(origin)) {
89 logger.debug("Invalid origin");
90 response = new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.BAD_REQUEST);
91 } else if (referer != null && !this.originValidator.isValidReferer(referer)) {
92 logger.debug("Invalid referer");
93 response = new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.BAD_REQUEST);
94 }
95 else {
96 ctx.fireChannelRead(request);
97 return;
98 }
99 } else {
100 response = new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.NOT_IMPLEMENTED);
101 }
102
103 ctx.write(response).addListener(ChannelFutureListener.CLOSE);
104 }
105
106 private String parseHostHeader(String hostHeader) {
107 try {
108 // WORKAROUND: add any scheme to make the resulting URI valid.
109 URI uri = new URI("my://" + hostHeader); // may throw URISyntaxException
110 return uri.getHost();
111 } catch (URISyntaxException e) {
112 return hostHeader;
113 }
114 }
115
116 private boolean isAcceptedAddress(final InetAddress address) {
117 // Check if the address is a valid special local or loop back
118 if (address.isLoopbackAddress() ) {
119 return true;
120 }
121 // Check if the address is defined on any interface
122 try {
123 return !address.isAnyLocalAddress() && NetworkInterface.getByInetAddress(address) != null;
124 } catch (SocketException se) {
125 return false;
126 }
127 }
128
129 }