Skip to content

Commit 7778c20

Browse files
committed
Merge remote-tracking branch 'origin/master'
2 parents 4754957 + 1203333 commit 7778c20

File tree

4 files changed

+115
-4
lines changed

4 files changed

+115
-4
lines changed

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,4 @@ JWS Utilties
1818
<artifactId>web-utils</artifactId>
1919
<version>1.0.0</version>
2020
</dependency>
21-
```
21+
```
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
package org.javawebstack.webutils.middlewares;
2+
3+
import org.javawebstack.httpserver.Exchange;
4+
import org.javawebstack.httpserver.handler.Middleware;
5+
6+
import java.util.HashMap;
7+
import java.util.Map;
8+
import java.util.Timer;
9+
import java.util.TimerTask;
10+
import java.util.concurrent.ConcurrentHashMap;
11+
12+
public class RateLimitMiddleware implements Middleware {
13+
private int rateLimit;
14+
private long millis;
15+
private Map<String, RateLimit> rateLimits = new ConcurrentHashMap<>();
16+
17+
public RateLimitMiddleware(long millis, int rateLimit){
18+
this.rateLimit = rateLimit;
19+
this.millis = millis;
20+
}
21+
22+
public RateLimitMiddleware(long millis){
23+
this(millis, 1);
24+
}
25+
26+
public Object handle(Exchange exchange) {
27+
String ip = exchange.rawRequest().getRemoteAddr();
28+
if (exchange.header("X-Forwarded-For") != null)
29+
ip = exchange.header("X-Forwarded-For");
30+
RateLimit rateLimit = null;
31+
if (rateLimits.containsKey(ip)) {
32+
rateLimit = rateLimits.get(ip);
33+
if (rateLimit.stillAlive() && rateLimit.getAndDecrease() <= 1)
34+
throw new RateLimitException();
35+
}
36+
if (rateLimit == null || !rateLimit.stillAlive())
37+
rateLimit = new RateLimit(System.currentTimeMillis() + millis, this.rateLimit);
38+
rateLimits.put(ip, rateLimit);
39+
exchange.header("X-Rate-Limit-Limit", String.valueOf(this.rateLimit));
40+
exchange.header("X-Rate-Limit-Remaining", String.valueOf(rateLimit.getRateLimitLeft()));
41+
exchange.header("X-Rate-Limit-Reset", String.valueOf(rateLimit.getTimeMillis()/1000));
42+
return null;
43+
}
44+
45+
public void removeDeadRateLimits(){
46+
rateLimits.forEach((ip, rateLimit)-> {
47+
if (!rateLimit.stillAlive())
48+
rateLimits.remove(ip);
49+
});
50+
}
51+
52+
public RateLimitMiddleware createAutoDeadRateLimitsRemover(long millis){
53+
new Timer().schedule(new TimerTask() {
54+
public void run() {
55+
removeDeadRateLimits();
56+
}
57+
}, millis, millis);
58+
return this;
59+
}
60+
61+
public RateLimitMiddleware createAutoDeadRateLimitsRemover(){
62+
return createAutoDeadRateLimitsRemover(millis);
63+
}
64+
65+
public int getRateLimit() {
66+
return rateLimit;
67+
}
68+
69+
public long getMillis() {
70+
return millis;
71+
}
72+
73+
public void setRateLimit(int rateLimit) {
74+
this.rateLimit = rateLimit;
75+
}
76+
77+
public void setMillis(int millis) {
78+
this.millis = millis;
79+
}
80+
81+
private static class RateLimit {
82+
private long timeMillis;
83+
private int rateLimitLeft;
84+
85+
private RateLimit(long timeMillis, int rateLimitLeft) {
86+
this.timeMillis = timeMillis;
87+
this.rateLimitLeft = rateLimitLeft;
88+
}
89+
90+
public int getRateLimitLeft() {
91+
return rateLimitLeft;
92+
}
93+
public int getAndDecrease() {
94+
return rateLimitLeft--;
95+
}
96+
97+
public long getTimeMillis() {
98+
return timeMillis;
99+
}
100+
101+
public boolean stillAlive(){
102+
return timeMillis > System.currentTimeMillis();
103+
}
104+
}
105+
106+
public static class RateLimitException extends RuntimeException {}
107+
}

src/main/java/org/javawebstack/webutils/util/URLUtils.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
public class URLUtils {
1010

11-
public String urlEncode(String content) {
11+
public static String urlEncode(String content) {
1212
try {
1313
return URLEncoder.encode(content, "UTF-8");
1414
} catch (UnsupportedEncodingException e) {
@@ -17,7 +17,7 @@ public String urlEncode(String content) {
1717
return null;
1818
}
1919

20-
public String urlDecode(String content) {
20+
public static String urlDecode(String content) {
2121
try {
2222
return URLDecoder.decode(content, "UTF-8");
2323
} catch (UnsupportedEncodingException e) {
@@ -119,7 +119,7 @@ public static URLBuilder from(String url) {
119119
String[] queryParameters = pathAndQueryParameters[1].split("&");
120120
for (String queryParameter : queryParameters) {
121121
String[] keyValue = queryParameter.split("=", 2);
122-
urlBuilder.queryParameters.set(keyValue[0], keyValue.length > 1 ? keyValue[1] : "");
122+
urlBuilder.queryParameters.set(URLUtils.urlDecode(keyValue[0]), URLUtils.urlDecode(keyValue.length > 1 ? keyValue[1] : ""));
123123
}
124124
}
125125
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
package org.javawebstack.webutils.test;
2+
3+
public class URLUtilsTests {
4+
}

0 commit comments

Comments
 (0)