1 package org
.argeo
.cms
.http
.server
;
3 import java
.io
.BufferedReader
;
4 import java
.io
.IOException
;
5 import java
.io
.InputStreamReader
;
6 import java
.io
.UncheckedIOException
;
8 import java
.net
.URLDecoder
;
9 import java
.nio
.charset
.Charset
;
10 import java
.nio
.charset
.StandardCharsets
;
11 import java
.util
.ArrayList
;
12 import java
.util
.HashMap
;
13 import java
.util
.List
;
15 import java
.util
.Objects
;
17 import org
.argeo
.api
.acr
.ContentRepository
;
18 import org
.argeo
.api
.acr
.ContentSession
;
19 import org
.argeo
.cms
.auth
.RemoteAuthUtils
;
20 import org
.argeo
.cms
.http
.HttpMethod
;
21 import org
.argeo
.cms
.internal
.http
.RemoteAuthHttpExchange
;
23 import com
.sun
.net
.httpserver
.HttpContext
;
24 import com
.sun
.net
.httpserver
.HttpExchange
;
26 /** HTTP utilities on the server-side. */
27 public class HttpServerUtils
{
28 private final static String SLASH
= "/";
30 private static String
extractPathWithingContext(HttpContext httpContext
, String fullPath
, boolean startWithSlash
) {
31 Objects
.requireNonNull(fullPath
);
32 String contextPath
= httpContext
.getPath();
33 if (!fullPath
.startsWith(contextPath
))
34 throw new IllegalArgumentException(fullPath
+ " does not belong to context" + contextPath
);
35 String path
= fullPath
.substring(contextPath
.length());
37 if (!startWithSlash
&& path
.startsWith(SLASH
)) {
38 path
= path
.substring(1);
39 } else if (startWithSlash
&& !path
.startsWith(SLASH
)) {
45 /** Path within the context, NOT starting with a slash. */
46 public static String
relativize(HttpExchange exchange
) {
47 URI uri
= exchange
.getRequestURI();
48 HttpContext httpContext
= exchange
.getHttpContext();
49 return extractPathWithingContext(httpContext
, uri
.getPath(), false);
52 /** Path within the context, starting with a slash. */
53 public static String
subPath(HttpExchange exchange
) {
54 URI uri
= exchange
.getRequestURI();
55 HttpContext httpContext
= exchange
.getHttpContext();
56 return extractPathWithingContext(httpContext
, uri
.getPath(), true);
59 /** Returns content session consistent with this HTTP context. */
60 public static ContentSession
getContentSession(ContentRepository contentRepository
, HttpExchange exchange
) {
61 ContentSession session
= RemoteAuthUtils
.doAs(() -> contentRepository
.get(),
62 new RemoteAuthHttpExchange(exchange
));
69 /** Returns the HTTP parameters form an {@link HttpExchange}. */
70 public static Map
<String
, List
<String
>> parseParameters(HttpExchange exchange
) {
71 // TODO check encoding?
72 Charset encoding
= StandardCharsets
.UTF_8
;
74 Map
<String
, List
<String
>> parameters
= new HashMap
<>();
75 URI requestedUri
= exchange
.getRequestURI();
76 String query
= requestedUri
.getRawQuery();
77 parseQuery(query
, parameters
, encoding
);
79 // TODO do we really want to support POST?
80 if (HttpMethod
.POST
.name().equalsIgnoreCase(exchange
.getRequestMethod())) {
83 // We do not close the stream on purpose, since the body still needs to be read
84 BufferedReader br
= new BufferedReader(new InputStreamReader(exchange
.getRequestBody(), encoding
));
85 postQuery
= br
.readLine();
86 } catch (IOException e
) {
87 throw new UncheckedIOException("Cannot read exchange body", e
);
89 parseQuery(postQuery
, parameters
, encoding
);
94 private static void parseQuery(String query
, Map
<String
, List
<String
>> parameters
, Charset encoding
) {
97 String pairs
[] = query
.split("[&]");
98 for (String pair
: pairs
) {
99 String param
[] = pair
.split("[=]");
103 if (param
.length
> 0) {
104 key
= URLDecoder
.decode(param
[0], encoding
);
107 if (param
.length
> 1) {
108 value
= URLDecoder
.decode(param
[1], encoding
);
111 if (!parameters
.containsKey(key
))
112 parameters
.put(key
, new ArrayList
<>());
113 parameters
.get(key
).add(value
);
118 private HttpServerUtils() {