Skip to content

Commit c0eb522

Browse files
authored
Merge pull request #1 from GoodforGod/dev
[0.10.0]
2 parents eb08f81 + 1d54bb8 commit c0eb522

File tree

4 files changed

+526
-4
lines changed

4 files changed

+526
-4
lines changed

README.md

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,19 +12,19 @@ Have no dependencies.
1212

1313
## Dependency :rocket:
1414

15-
Java 17+
15+
Java 17+ support.
1616

1717
[**Gradle**](https://mvnrepository.com/artifact/io.goodforgod/http-common)
1818
```groovy
19-
implementation "io.goodforgod:http-common:0.9.0"
19+
implementation "io.goodforgod:http-common:0.10.0"
2020
```
2121

2222
[**Maven**](https://mvnrepository.com/artifact/io.goodforgod/http-common)
2323
```xml
2424
<dependency>
2525
<groupId>io.goodforgod</groupId>
2626
<artifactId>http-common</artifactId>
27-
<version>0.9.0</version>
27+
<version>0.10.0</version>
2828
</dependency>
2929
```
3030

@@ -41,6 +41,15 @@ String reason = status.reason();
4141
HttpStatus statusAccepted = HttpStatus.valueOf(201);
4242
```
4343

44+
## HttpMethod
45+
46+
Describes *HttpMethod* common methods of HTTP protocol.
47+
48+
```java
49+
final HttpMethod method = HttpMethod.of("get");
50+
assertEquarls(HttpMethod.GET, method);
51+
```
52+
4453
## MediaType
4554

4655
Library provides *MediaType* class for correctly parsing and interpreting MediaType / ContentTypes.
@@ -66,6 +75,22 @@ URIBuilder.of("https://api.etherscan.io").path("/api")
6675
.build()
6776
```
6877

78+
## HttpHeaders
79+
80+
Describes HTTP headers and can be instantiated via different builders available.
81+
82+
```java
83+
final Map<String, List<String>> h = new HashMap<>();
84+
h.put(HttpHeaders.CONNECTION, List.of("keep-alive"));
85+
h.put(HttpHeaders.CONTENT_LENGTH, List.of("72"));
86+
h.put(HttpHeaders.CONTENT_TYPE, List.of("application/json"));
87+
88+
final HttpHeaders headers = HttpHeaders.ofMultiMap(h);
89+
90+
final Optional<Long> contentLength = headers.contentLength();
91+
final Optional<MediaType> mediaType = headers.contentType();
92+
```
93+
6994
## License
7095

7196
This project licensed under the Apache License 2.0 - see the [LICENSE](LICENSE) file for details

gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
groupId=io.goodforgod
22
artifactId=http-common
3-
artifactVersion=0.9.0
3+
artifactVersion=0.10.0
44

55

66
##### GRADLE #####
Lines changed: 293 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,293 @@
1+
package io.goodforgod.http.common;
2+
3+
import java.util.*;
4+
import java.util.stream.Collectors;
5+
import org.jetbrains.annotations.NotNull;
6+
import org.jetbrains.annotations.Nullable;
7+
8+
/**
9+
* Constants for common HTTP headers.
10+
* <a href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html">W3</a>
11+
*
12+
* @author Anton Kurako (GoodforGod)
13+
* @since 13.03.2022
14+
*/
15+
public final class HttpHeaders {
16+
17+
public static final String ACCEPT = "Accept";
18+
public static final String ACCEPT_CH = "Accept-CH";
19+
public static final String ACCEPT_CH_LIFETIME = "Accept-CH-Lifetime";
20+
public static final String ACCEPT_CHARSET = "Accept-Charset";
21+
public static final String ACCEPT_ENCODING = "Accept-Encoding";
22+
public static final String ACCEPT_LANGUAGE = "Accept-Language";
23+
public static final String ACCEPT_RANGES = "Accept-Ranges";
24+
public static final String ACCEPT_PATCH = "Accept-Patch";
25+
public static final String ACCESS_CONTROL_ALLOW_CREDENTIALS = "Access-Control-Allow-Credentials";
26+
public static final String ACCESS_CONTROL_ALLOW_HEADERS = "Access-Control-Allow-Headers";
27+
public static final String ACCESS_CONTROL_ALLOW_METHODS = "Access-Control-Allow-Methods";
28+
public static final String ACCESS_CONTROL_ALLOW_ORIGIN = "Access-Control-Allow-Origin";
29+
public static final String ACCESS_CONTROL_EXPOSE_HEADERS = "Access-Control-Expose-Headers";
30+
public static final String ACCESS_CONTROL_MAX_AGE = "Access-Control-Max-Age";
31+
public static final String ACCESS_CONTROL_REQUEST_HEADERS = "Access-Control-Request-Headers";
32+
public static final String ACCESS_CONTROL_REQUEST_METHOD = "Access-Control-Request-Method";
33+
public static final String AGE = "Age";
34+
public static final String ALLOW = "Allow";
35+
public static final String AUTHORIZATION = "Authorization";
36+
public static final String AUTHORIZATION_INFO = "Authorization-Info";
37+
public static final String CACHE_CONTROL = "Cache-Control";
38+
public static final String CONNECTION = "Connection";
39+
public static final String CONTENT_BASE = "Content-Base";
40+
public static final String CONTENT_DISPOSITION = "Content-Disposition";
41+
public static final String CONTENT_DPR = "Content-DPR";
42+
public static final String CONTENT_ENCODING = "Content-Encoding";
43+
public static final String CONTENT_LANGUAGE = "Content-Language";
44+
public static final String CONTENT_LENGTH = "Content-Length";
45+
public static final String CONTENT_LOCATION = "Content-Location";
46+
public static final String CONTENT_TRANSFER_ENCODING = "Content-Transfer-Encoding";
47+
public static final String CONTENT_MD5 = "Content-MD5";
48+
public static final String CONTENT_RANGE = "Content-Range";
49+
public static final String CONTENT_TYPE = "Content-Type";
50+
public static final String COOKIE = "Cookie";
51+
public static final String CROSS_ORIGIN_RESOURCE_POLICY = "Cross-Origin-Resource-Policy";
52+
public static final String DATE = "Date";
53+
public static final String DEVICE_MEMORY = "Device-Memory";
54+
public static final String DOWNLINK = "Downlink";
55+
public static final String DPR = "DPR";
56+
public static final String ECT = "ECT";
57+
public static final String ETAG = "ETag";
58+
public static final String EXPECT = "Expect";
59+
public static final String EXPIRES = "Expires";
60+
public static final String FEATURE_POLICY = "Feature-Policy";
61+
public static final String FORWARDED = "Forwarded";
62+
public static final String FROM = "From";
63+
public static final String HOST = "Host";
64+
public static final String IF_MATCH = "If-Match";
65+
public static final String IF_MODIFIED_SINCE = "If-Modified-Since";
66+
public static final String IF_NONE_MATCH = "If-None-Match";
67+
public static final String IF_RANGE = "If-Range";
68+
public static final String IF_UNMODIFIED_SINCE = "If-Unmodified-Since";
69+
public static final String LAST_MODIFIED = "Last-Modified";
70+
public static final String LINK = "Link";
71+
public static final String LOCATION = "Location";
72+
public static final String MAX_FORWARDS = "Max-Forwards";
73+
public static final String ORIGIN = "Origin";
74+
public static final String PRAGMA = "Pragma";
75+
public static final String PROXY_AUTHENTICATE = "Proxy-Authenticate";
76+
public static final String PROXY_AUTHORIZATION = "Proxy-Authorization";
77+
public static final String RANGE = "Range";
78+
public static final String REFERER = "Referer";
79+
public static final String REFERRER_POLICY = "Referrer-Policy";
80+
public static final String RETRY_AFTER = "Retry-After";
81+
public static final String RTT = "RTT";
82+
public static final String SAVE_DATA = "Save-Data";
83+
public static final String SEC_WEBSOCKET_KEY1 = "Sec-WebSocket-Key1";
84+
public static final String SEC_WEBSOCKET_KEY2 = "Sec-WebSocket-Key2";
85+
public static final String SEC_WEBSOCKET_LOCATION = "Sec-WebSocket-Location";
86+
public static final String SEC_WEBSOCKET_ORIGIN = "Sec-WebSocket-Origin";
87+
public static final String SEC_WEBSOCKET_PROTOCOL = "Sec-WebSocket-Protocol";
88+
public static final String SEC_WEBSOCKET_VERSION = "Sec-WebSocket-Version";
89+
public static final String SEC_WEBSOCKET_KEY = "Sec-WebSocket-Key";
90+
public static final String SEC_WEBSOCKET_ACCEPT = "Sec-WebSocket-Accept";
91+
public static final String SERVER = "Server";
92+
public static final String SET_COOKIE = "Set-Cookie";
93+
public static final String SET_COOKIE2 = "Set-Cookie2";
94+
public static final String SOURCE_MAP = "SourceMap";
95+
public static final String TE = "TE";
96+
public static final String TRAILER = "Trailer";
97+
public static final String TRANSFER_ENCODING = "Transfer-Encoding";
98+
public static final String UPGRADE = "Upgrade";
99+
public static final String USER_AGENT = "User-Agent";
100+
public static final String VARY = "Vary";
101+
public static final String VIA = "Via";
102+
public static final String VIEWPORT_WIDTH = "Viewport-Width";
103+
public static final String WARNING = "Warning";
104+
public static final String WEBSOCKET_LOCATION = "WebSocket-Location";
105+
public static final String WEBSOCKET_ORIGIN = "WebSocket-Origin";
106+
public static final String WEBSOCKET_PROTOCOL = "WebSocket-Protocol";
107+
public static final String WIDTH = "Width";
108+
public static final String WWW_AUTHENTICATE = "WWW-Authenticate";
109+
public static final String X_AUTH_TOKEN = "X-Auth-Token";
110+
111+
private static final HttpHeaders EMPTY = new HttpHeaders(Collections.emptyMap());
112+
113+
private final Map<String, List<String>> multiHeaderMap;
114+
115+
private HttpHeaders(@NotNull Map<String, List<String>> multiHeaderMap) {
116+
this.multiHeaderMap = multiHeaderMap;
117+
}
118+
119+
@NotNull
120+
public static HttpHeaders ofMultiMap(@Nullable Map<String, List<String>> multiHeaderMap) {
121+
if (multiHeaderMap == null || multiHeaderMap.isEmpty()) {
122+
return EMPTY;
123+
}
124+
125+
final Map<String, List<String>> headers = Map.copyOf(multiHeaderMap.entrySet().stream()
126+
.filter(e -> e.getKey() != null && !e.getKey().isEmpty()
127+
&& e.getValue() != null && !e.getValue().isEmpty())
128+
.collect(Collectors.toMap(Map.Entry::getKey, e -> List.copyOf(e.getValue()))));
129+
130+
return new HttpHeaders(headers);
131+
}
132+
133+
@NotNull
134+
public static HttpHeaders ofMap(@Nullable Map<String, String> headerMap) {
135+
if (headerMap == null || headerMap.isEmpty()) {
136+
return EMPTY;
137+
}
138+
139+
final Map<String, List<String>> headers = Map.copyOf(headerMap.entrySet().stream()
140+
.filter(e -> e.getKey() != null && !e.getKey().isEmpty()
141+
&& e.getValue() != null)
142+
.collect(Collectors.toMap(Map.Entry::getKey, e -> List.of(e.getValue()))));
143+
144+
return new HttpHeaders(headers);
145+
}
146+
147+
@NotNull
148+
public static HttpHeaders of(@Nullable String... headerAndValue) {
149+
if (headerAndValue == null || headerAndValue.length == 0) {
150+
return EMPTY;
151+
}
152+
153+
final boolean isEven = headerAndValue.length % 2 == 0;
154+
if (!isEven) {
155+
throw new IllegalArgumentException("Header and values amount must be even, but was: " + headerAndValue.length);
156+
}
157+
158+
final Map<String, List<String>> multiHeaderMap = new HashMap<>(headerAndValue.length + 5);
159+
for (int i = 0; i < headerAndValue.length; i += 2) {
160+
final String key = headerAndValue[i];
161+
final String value = headerAndValue[i + 1];
162+
if (key != null && value != null) {
163+
multiHeaderMap.put(key, List.of(value));
164+
}
165+
}
166+
167+
final Map<String, List<String>> headers = Map.copyOf(multiHeaderMap);
168+
return new HttpHeaders(headers);
169+
}
170+
171+
@NotNull
172+
public static HttpHeaders empty() {
173+
return EMPTY;
174+
}
175+
176+
/**
177+
* Get the first value of the given header.
178+
*
179+
* @param headerName The header name
180+
* @return The first value or null if it is present
181+
*/
182+
@NotNull
183+
public Optional<String> findFirst(@NotNull CharSequence headerName) {
184+
final List<String> values = multiHeaderMap.get(headerName.toString());
185+
if (values == null) {
186+
return Optional.empty();
187+
}
188+
189+
return Optional.of(values.get(0));
190+
}
191+
192+
/**
193+
* Find all values of the given header.
194+
*
195+
* @param headerName The header name
196+
* @return All values or empty list if not present
197+
*/
198+
@NotNull
199+
public List<String> findAll(@NotNull CharSequence headerName) {
200+
return multiHeaderMap.getOrDefault(headerName.toString(), Collections.emptyList());
201+
}
202+
203+
/**
204+
* @return all headers and values as multi map
205+
*/
206+
@NotNull
207+
public Map<String, List<String>> getMultiMap() {
208+
return multiHeaderMap;
209+
}
210+
211+
/**
212+
* @return all headers and only first corresponding value as map
213+
*/
214+
@NotNull
215+
public Map<String, String> getMap() {
216+
return multiHeaderMap.entrySet().stream()
217+
.collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().iterator().next()));
218+
}
219+
220+
/**
221+
* The request or response content type.
222+
*
223+
* @return The content type
224+
*/
225+
@NotNull
226+
public Optional<Long> contentLength() {
227+
return findFirst(CONTENT_LENGTH)
228+
.map(Long::parseLong);
229+
}
230+
231+
/**
232+
* The request or response content type.
233+
*
234+
* @return The content type
235+
*/
236+
@NotNull
237+
public Optional<MediaType> contentType() {
238+
return findFirst(CONTENT_TYPE).map(MediaType::of);
239+
}
240+
241+
/**
242+
* @return The {@link #ORIGIN} header
243+
*/
244+
@NotNull
245+
public Optional<String> origin() {
246+
return findFirst(ORIGIN);
247+
}
248+
249+
/**
250+
* @return The {@link #AUTHORIZATION} header
251+
*/
252+
@NotNull
253+
public Optional<String> authorization() {
254+
return findFirst(AUTHORIZATION);
255+
}
256+
257+
/**
258+
* @return Whether the {@link HttpHeaders#CONNECTION} header is set to Keep-Alive
259+
*/
260+
public boolean isKeepAlive() {
261+
return findFirst(CONNECTION)
262+
.map(v -> v.equalsIgnoreCase("keep-alive"))
263+
.orElse(false);
264+
}
265+
266+
/**
267+
* A list of accepted {@link MediaType} instances.
268+
*
269+
* @return A list of zero or many {@link MediaType} instances
270+
*/
271+
@NotNull
272+
public List<MediaType> accept() {
273+
final List<String> values = findAll(ACCEPT);
274+
if (values.isEmpty()) {
275+
return Collections.emptyList();
276+
}
277+
278+
final List<MediaType> mediaTypes = new ArrayList<>(6);
279+
for (String value : values) {
280+
for (String token : value.split(",")) {
281+
if (!token.isEmpty()) {
282+
try {
283+
mediaTypes.add(MediaType.of(token));
284+
} catch (IllegalArgumentException e) {
285+
// ignore
286+
}
287+
}
288+
}
289+
}
290+
291+
return mediaTypes;
292+
}
293+
}

0 commit comments

Comments
 (0)