package core.framework.impl.web.request;
import core.framework.api.http.ContentType;
import core.framework.api.http.HTTPMethod;
import core.framework.api.util.Encodings;
import core.framework.api.util.Exceptions;
import core.framework.api.util.Maps;
import core.framework.api.web.CookieSpec;
import core.framework.api.web.MultipartFile;
import core.framework.api.web.Request;
import core.framework.api.web.Session;
import core.framework.api.web.exception.BadRequestException;
import core.framework.impl.json.JSONMapper;
import core.framework.impl.web.BeanValidator;
import io.undertow.server.HttpServerExchange;
import io.undertow.server.handlers.Cookie;
import java.io.UncheckedIOException;
import java.lang.reflect.Type;
import java.util.Map;
import java.util.Optional;
/**
* @author neo
*/
public final class RequestImpl implements Request {
public final PathParams pathParams = new PathParams();
final Map<String, String> queryParams = Maps.newHashMap();
final Map<String, String> formParams = Maps.newHashMap();
final Map<String, MultipartFile> files = Maps.newHashMap();
private final HttpServerExchange exchange;
private final BeanValidator validator;
public Session session;
HTTPMethod method;
String clientIP;
String scheme;
int port;
String requestURL;
ContentType contentType;
byte[] body;
public RequestImpl(HttpServerExchange exchange, BeanValidator validator) {
this.exchange = exchange;
this.validator = validator;
}
@Override
public String requestURL() {
return requestURL;
}
@Override
public String scheme() {
return scheme;
}
@Override
public String hostName() {
return exchange.getHostName();
}
@Override
public String path() { // exchange returns decoded path
return exchange.getRequestPath();
}
@Override
public String clientIP() {
return clientIP;
}
@Override
public Optional<String> cookie(CookieSpec spec) {
Cookie cookie = exchange.getRequestCookies().get(spec.name);
if (cookie == null) return Optional.empty();
try {
return Optional.of(Encodings.decodeURIComponent(cookie.getValue()));
} catch (IllegalArgumentException e) {
throw new BadRequestException(e.getMessage(), BadRequestException.DEFAULT_ERROR_CODE, e);
}
}
@Override
public Session session() {
if (!"https".equals(scheme)) throw new Error("session must be used under https");
if (session == null) throw new Error("site().session() must be configured");
return session;
}
@Override
public HTTPMethod method() {
return method;
}
@Override
public Optional<String> header(String name) {
return Optional.ofNullable(exchange.getRequestHeaders().getFirst(name));
}
@Override
public <T> T pathParam(String name, Class<T> valueClass) {
String value = pathParams.get(name);
return URLParamParser.parse(value, valueClass);
}
@Override
public <T> Optional<T> queryParam(String name, Class<T> valueClass) {
String value = queryParams.get(name);
if (value == null) return Optional.empty();
return Optional.of(URLParamParser.parse(value, valueClass));
}
@Override
public Map<String, String> queryParams() {
return queryParams;
}
@Override
public Optional<String> formParam(String name) {
return Optional.ofNullable(formParams.get(name));
}
@Override
public Map<String, String> formParams() {
return formParams;
}
@Override
public Optional<MultipartFile> file(String name) {
return Optional.ofNullable(files.get(name));
}
@Override
public Map<String, MultipartFile> files() {
return files;
}
@Override
public Optional<byte[]> body() {
return Optional.ofNullable(body);
}
@Override
public <T> T bean(Type instanceType) {
try {
T bean = parseBean(instanceType);
return validator.validate(instanceType, bean);
} catch (UncheckedIOException e) {
throw new BadRequestException(e.getMessage(), BadRequestException.DEFAULT_ERROR_CODE, e);
}
}
private <T> T parseBean(Type instanceType) {
if (method == HTTPMethod.GET || method == HTTPMethod.DELETE) {
return JSONMapper.fromMapValue(instanceType, queryParams);
} else if (method == HTTPMethod.POST || method == HTTPMethod.PUT) {
if (!formParams.isEmpty()) {
return JSONMapper.fromMapValue(instanceType, formParams);
} else if (body != null && contentType != null && ContentType.APPLICATION_JSON.mediaType().equals(contentType.mediaType())) {
return JSONMapper.fromJSON(instanceType, body);
}
throw new BadRequestException("body is missing or unsupported content type, method=" + method + ", contentType=" + contentType);
} else {
throw Exceptions.error("not supported method, method={}", method);
}
}
}