/* * Copyright 2017 The OpenDSP Project * * The OpenDSP Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package ai.houyi.dorado.rest.http.impl; import java.io.InputStream; import java.net.InetSocketAddress; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; import ai.houyi.dorado.netty.ext.HttpPostRequestDecoder; import ai.houyi.dorado.rest.http.HttpRequest; import ai.houyi.dorado.rest.http.MultipartFile; import ai.houyi.dorado.rest.util.LogUtils; import ai.houyi.dorado.rest.util.NetUtils; import ai.houyi.dorado.rest.util.StringUtils; import io.netty.handler.codec.http.FullHttpRequest; import io.netty.handler.codec.http.HttpHeaderNames; import io.netty.handler.codec.http.HttpHeaders; import io.netty.handler.codec.http.HttpMethod; import io.netty.handler.codec.http.QueryStringDecoder; import io.netty.handler.codec.http.cookie.Cookie; import io.netty.handler.codec.http.cookie.ServerCookieDecoder; import io.netty.handler.codec.http.multipart.Attribute; import io.netty.handler.codec.http.multipart.FileUpload; import io.netty.handler.codec.http.multipart.InterfaceHttpData; import io.netty.handler.codec.http.multipart.InterfaceHttpData.HttpDataType; /** * * @author wangwp */ public class HttpRequestImpl implements HttpRequest { private final FullHttpRequest request; private final InputStreamImpl in; private final QueryStringDecoder queryStringDecoder; private final URIParser uriParser; private final Map<String, List<String>> parameters; private final HttpHeaders headers; private final List<MultipartFile> multipartFiles; public HttpRequestImpl(FullHttpRequest request) { this.request = request; this.parameters = new HashMap<>(); this.headers = request.headers(); this.multipartFiles = new ArrayList<>(); this.uriParser = new URIParser(); // 解析querystring上面的参数 queryStringDecoder = new QueryStringDecoder(request.uri()); uriParser.parse(queryStringDecoder.path()); parameters.putAll(queryStringDecoder.parameters()); in = new InputStreamImpl(request); if (request.method() == HttpMethod.POST) { parseHttpPostRequest(request); } } private void parseHttpPostRequest(FullHttpRequest request) { HttpPostRequestDecoder decoder = null; try { decoder = new HttpPostRequestDecoder(request); for (InterfaceHttpData httpData : decoder.getBodyHttpDatas()) { HttpDataType _type = httpData.getHttpDataType(); if (_type == HttpDataType.Attribute) { Attribute attribute = (Attribute) httpData; parseAttribute(attribute); } else if (_type == HttpDataType.FileUpload) { FileUpload upload = (FileUpload) httpData; multipartFiles.add(MultipartFileFactory.create(upload)); } } } catch (Exception ex) { LogUtils.warn(ex.getMessage()); } finally { // 注意这个地方,一定要调用destroy方法,如果不调用会导致内存泄漏 if (decoder != null) decoder.destroy(); } } private void parseAttribute(Attribute attribute) throws Exception { if (this.parameters.containsKey(attribute.getName())) { this.parameters.get(attribute.getName()).add(attribute.getValue()); } else { List<String> values = new ArrayList<>(); values.add(attribute.getValue()); this.parameters.put(attribute.getName(), values); } } @Override public String getParameter(String key) { List<String> parameterValues = parameters.get(key); return (parameterValues == null || parameterValues.isEmpty()) ? null : parameterValues.get(0); } @Override public String[] getParameterValues(String key) { return this.parameters.get(key).toArray(new String[] {}); } @Override public Map<String, List<String>> getParameters() { return this.parameters; } @Override public String getRemoteAddr() { InetSocketAddress addr = (InetSocketAddress) ChannelHolder.get().remoteAddress(); String fallbackAddr = addr.getAddress().getHostAddress(); String xForwardFor = headers.get("X-Forwarded-For"); if (xForwardFor == null || StringUtils.isBlank(xForwardFor)) { return fallbackAddr; } String[] proxyIpList = xForwardFor.split(","); for (int i = proxyIpList.length - 1; i >= 0; i--) { String proxyIp = proxyIpList[i]; if (!StringUtils.isBlank(proxyIp)) proxyIp = proxyIp.trim(); if (!NetUtils.isInternalIp(proxyIp)) { return proxyIp; } } return fallbackAddr; } @Override public ai.houyi.dorado.rest.http.Cookie[] getCookies() { String cookieString = this.request.headers().get(HttpHeaderNames.COOKIE); if (cookieString != null) { Set<Cookie> cookies = ServerCookieDecoder.LAX.decode(cookieString); return cookies.stream().map(cookie -> new CookieImpl(cookie)).collect(Collectors.toList()) .toArray(new CookieImpl[] {}); } return null; } @Override public String getHeader(String name) { return headers.get(name); } @Override public String[] getHeaders(String name) { return headers.getAll(name).toArray(new String[] {}); } @Override public String getQueryString() { return uriParser.getQueryString(); } @Override public String getRequestURI() { return uriParser.getRequestUri(); } @Override public String getMethod() { return this.request.method().name(); } @Override public InputStream getInputStream() { return this.in; } public MultipartFile getFile() { if (multipartFiles != null && !multipartFiles.isEmpty()) { return multipartFiles.get(0); } return null; } public MultipartFile[] getFiles() { if (multipartFiles != null && !multipartFiles.isEmpty()) { return multipartFiles.toArray(new MultipartFile[] {}); } return null; } public List<MultipartFile> getFileList() { return multipartFiles; } }