//------------------------------------------------- // Litchi Game Server Framework // Copyright(c) 2019 phantaci <[email protected]> // MIT Licensed //------------------------------------------------- package litchi.core.net.http.server; import static io.netty.handler.codec.http.HttpHeaderNames.CONTENT_TYPE; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Optional; import litchi.core.common.utils.ObjectUtils; import litchi.core.common.utils.StringUtils; import litchi.core.net.http.server.router.RouteAction; import litchi.core.net.http.server.router.RouteResult; import litchi.core.net.session.ChannelUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.serializer.SerializerFeature; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.Channel; import io.netty.handler.codec.http.DefaultFullHttpResponse; import io.netty.handler.codec.http.FullHttpRequest; import io.netty.handler.codec.http.HttpHeaderNames; import io.netty.handler.codec.http.HttpMethod; import io.netty.handler.codec.http.HttpResponse; import io.netty.handler.codec.http.HttpResponseStatus; import io.netty.handler.codec.http.HttpUtil; import io.netty.handler.codec.http.HttpVersion; import io.netty.handler.codec.http.cookie.Cookie; import io.netty.handler.codec.http.cookie.DefaultCookie; import io.netty.handler.codec.http.cookie.ServerCookieDecoder; import io.netty.handler.codec.http.cookie.ServerCookieEncoder; import io.netty.handler.codec.http.multipart.Attribute; import io.netty.handler.codec.http.multipart.FileUpload; import io.netty.handler.codec.http.multipart.HttpPostRequestDecoder; import io.netty.handler.codec.http.multipart.InterfaceHttpData; import io.netty.handler.codec.http.multipart.InterfaceHttpData.HttpDataType; import io.netty.handler.codec.http.multipart.MixedFileUpload; import io.netty.util.CharsetUtil; import litchi.core.common.utils.ObjectUtils; import litchi.core.common.utils.StringUtils; import litchi.core.net.http.server.router.RouteAction; import litchi.core.net.http.server.router.RouteResult; import litchi.core.net.session.ChannelUtils; public abstract class HttpController { protected Logger LOGGER = LoggerFactory.getLogger(getClass()); protected static String JSON_CONTENT_TYPE ="application/json;charset=UTF-8"; protected static String FILE_CONTENT_TYPE ="application/json;charset=UTF-8"; protected Channel channel; protected FullHttpRequest request; protected RouteResult<RouteAction> routeResult; private boolean enableCookies; private Map<String, String> postMaps = new HashMap<>(); private Map<String, Cookie> cookieMaps = new HashMap<>(); private FileUpload fileUpload; public Map<String, String> postMap() { return this.postMaps; } public Map<String, String> getMap() { return this.routeResult.pathParams(); } public Map<String, String> getParams() { Map<String, List<String>> queryParams = this.routeResult.queryParams(); Map<String, String> map = new HashMap<>(); for (Entry<String, List<String>> entry : queryParams.entrySet()) { Optional<String> optional = entry.getValue().stream().findFirst(); map.put(entry.getKey(), optional.orElse("")); } return map; } public FileUpload fileUpload() { return fileUpload; } public void init(Channel channel, FullHttpRequest request, RouteResult<RouteAction> routeResult, boolean enableCookies) { this.channel = channel; this.request = request; this.routeResult = routeResult; this.enableCookies = enableCookies; if (this.method() == HttpMethod.POST) { try { HttpPostRequestDecoder decoder = new HttpPostRequestDecoder(request); decoder.offer(request); List<InterfaceHttpData> paramsList = decoder.getBodyHttpDatas(); for (InterfaceHttpData httpData : paramsList) { if (httpData.getHttpDataType() == HttpDataType.Attribute) { Attribute data = (Attribute) httpData; postMaps.put(data.getName(), data.getValue()); } else if (httpData.getHttpDataType() == HttpDataType.FileUpload) { MixedFileUpload fileUpload = (MixedFileUpload) httpData; this.fileUpload = fileUpload; } else { LOGGER.error("not support http data type. type={}", httpData.getHttpDataType()); } } } catch (Exception ex) { LOGGER.error("{}", ex); } } if (enableCookies) { List<String> cookiesList = request.headers().getAll(HttpHeaderNames.COOKIE); cookiesList.forEach(h -> ServerCookieDecoder.STRICT.decode(h).forEach(c -> cookieMaps.put(c.name(), c))); } } public HttpMethod method() { return request.method(); } public <T> T get(String name, T defaultValue) { String result = routeResult.param(name); if (StringUtils.isBlank(result)) { return defaultValue; } T value = ObjectUtils.valueOf(result, defaultValue); if (value != null) { return value; } return defaultValue; } public String get(String name) { return get(name, ""); } public <T> T post(String name, T defaultValue) { String result = postMaps.get(name); if (StringUtils.isBlank(result)) { return defaultValue; } T value = ObjectUtils.valueOf(result, defaultValue); if (value != null) { return value; } return defaultValue; } public String post(String name) { return post(name, ""); } public String getRemoteIp() { return ChannelUtils.getRemoteIp(this.channel); } public void renderJson(Object object) { String json = JSON.toJSONString(object, SerializerFeature.IgnoreNonFieldGetter); write(json, JSON_CONTENT_TYPE); } public void jsonResponse(Object object) { String json = JSON.toJSONString(object); write(json, JSON_CONTENT_TYPE); } /** * write to response * * @param text */ public void render(String text) { write(text, "text/plain; charset=UTF-8"); } public void render(String text, String contentType) { write(text, contentType); } public void write(String text, String contentType) { ByteBuf content = Unpooled.copiedBuffer(text, CharsetUtil.UTF_8); HttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, content); response.headers().set(CONTENT_TYPE, contentType); if (enableCookies) { for (Map.Entry<String, Cookie> entry : cookieMaps.entrySet()) { response.headers().add(HttpHeaderNames.SET_COOKIE, ServerCookieEncoder.STRICT.encode(entry.getValue())); } } // 跨域支持 response.headers().add("Access-Control-Allow-Origin", "*"); response.headers().add("Access-Control-Allow-Methods", "POST"); HttpUtil.setContentLength(response, content.readableBytes()); channel.writeAndFlush(response); //.addListener(ChannelFutureListener.CLOSE); } public void writeFile(String fileName, String text) { ByteBuf content = Unpooled.copiedBuffer(text, CharsetUtil.UTF_8); HttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, content); response.headers().set("Pragma", "Pragma"); response.headers().set("Expires", "0"); response.headers().set("Cache-Control", "must-revalidate, post-check=0, pre-check=0"); response.headers().set("Content-Type", "application/download"); response.headers().set("Content-Disposition", "attachment;filename=" + fileName); response.headers().set("Content-Transfer-Encoding", "binary"); if (enableCookies) { for (Map.Entry<String, Cookie> entry : cookieMaps.entrySet()) { response.headers().add(HttpHeaderNames.SET_COOKIE, ServerCookieEncoder.STRICT.encode(entry.getValue())); } } // 跨域支持 response.headers().add("Access-Control-Allow-Origin", "*"); response.headers().add("Access-Control-Allow-Methods", "POST"); HttpUtil.setContentLength(response, content.readableBytes()); channel.writeAndFlush(response); //.addListener(ChannelFutureListener.CLOSE); } public String getCookie(String name, String defaultValue) { if (this.cookieMaps.containsKey(name)) { Cookie cookie = this.cookieMaps.get(name); return cookie.value(); } return defaultValue; } public String getCookie(String name) { return getCookie(name, ""); } public void setCookie(String name, String value) { setCookie(name, value, -1, ""); } public void setCookie(String name, String value, long maxAge, String domain) { Cookie cookie = this.cookieMaps.get(name); if (cookie == null) { cookie = new DefaultCookie(name, value); this.cookieMaps.put(name, cookie); } cookie.setValue(value); if (maxAge > 0) { cookie.setMaxAge(maxAge); } if (StringUtils.isBlank(domain)) { cookie.setDomain(domain); } } public Collection<Cookie> getCookieMaps() { return this.cookieMaps.values(); } }