All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.blade.mvc.http.HttpRequest Maven / Gradle / Ivy

There is a newer version: 2.0.15.RELEASE
Show newest version
/**
 * Copyright (c) 2018, biezhi 王爵 nice ([email protected])
 * 

* Licensed 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 com.blade.mvc.http; import com.blade.exception.HttpParseException; import com.blade.kit.PathKit; import com.blade.kit.StringKit; import com.blade.mvc.Const; import com.blade.mvc.WebContext; import com.blade.mvc.handler.SessionHandler; import com.blade.mvc.http.session.SessionManager; import com.blade.mvc.multipart.FileItem; import com.blade.mvc.route.Route; import com.blade.server.netty.HttpConst; import com.blade.server.netty.HttpServerHandler; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.handler.codec.http.*; import io.netty.handler.codec.http.cookie.ServerCookieDecoder; import io.netty.handler.codec.http.multipart.*; import io.netty.util.CharsetUtil; import lombok.NoArgsConstructor; import lombok.NonNull; import lombok.extern.slf4j.Slf4j; import lombok.var; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.StandardCopyOption; import java.util.*; /** * Http Request Impl * * @author biezhi * 2017/5/31 */ @Slf4j @NoArgsConstructor public class HttpRequest implements Request { private static final HttpDataFactory HTTP_DATA_FACTORY = new DefaultHttpDataFactory(true); // Disk if size exceed private static final ByteBuf EMPTY_BUF = Unpooled.copiedBuffer("", CharsetUtil.UTF_8); private static final SessionHandler SESSION_HANDLER = new SessionHandler(WebContext.blade()); static { DiskFileUpload.deleteOnExitTemporaryFile = true; // should delete file DiskFileUpload.baseDirectory = null; // system temp directory DiskAttribute.deleteOnExitTemporaryFile = true; // should delete file on DiskAttribute.baseDirectory = null; // system temp directory } private ByteBuf body = EMPTY_BUF; private String remoteAddress; private String uri; private String url; private String protocol; private String method; private boolean keepAlive; private Session session; private boolean isMultipart; private boolean isEnd; private boolean initCookie; private boolean initQueryParam; private HttpData partialContent; private HttpHeaders httpHeaders; private io.netty.handler.codec.http.HttpRequest nettyRequest; private HttpPostRequestDecoder decoder; private Queue contents = new LinkedList<>(); private Map headers = null; private Map attributes = null; private Map pathParams = null; private Map> parameters = new HashMap<>(8); private Map cookies = new HashMap<>(8); private Map fileItems = new HashMap<>(8); public HttpRequest(Request request) { this.pathParams = request.pathParams(); this.cookies = request.cookies(); this.attributes = request.attributes(); this.body = request.body(); this.fileItems = request.fileItems(); this.headers = request.headers(); this.keepAlive = request.keepAlive(); this.method = request.method(); this.url = request.url(); if (null != this.url && this.url.length() > 0) { var pathEndPos = this.url.indexOf('?'); this.uri = pathEndPos < 0 ? this.url : this.url.substring(0, pathEndPos); } this.parameters = request.parameters(); this.protocol = request.protocol(); } @Override public Request initPathParams(@NonNull Route route) { if (null != route.getPathParams()) this.pathParams = route.getPathParams(); return this; } @Override public String host() { return this.header("Host"); } @Override public String remoteAddress() { return this.remoteAddress; } @Override public String uri() { return this.uri; } @Override public String url() { return this.url; } @Override public String protocol() { return this.protocol; } @Override public Map pathParams() { return this.pathParams; } @Override public String queryString() { if (null == url || !url.contains("?")) { return ""; } return url.substring(url.indexOf("?") + 1); } @Override public Map> parameters() { if (initQueryParam) { return this.parameters; } initQueryParam = true; if (!url.contains("?")) { return this.parameters; } var parameters = new QueryStringDecoder(url, CharsetUtil.UTF_8).parameters(); if (null != parameters) { this.parameters.putAll(parameters); } return this.parameters; } @Override public Set parameterNames() { return this.parameters.keySet(); } @Override public List parameterValues(String paramName) { return this.parameters.get(paramName); } @Override public String method() { return this.method; } @Override public HttpMethod httpMethod() { return HttpMethod.valueOf(method()); } @Override public boolean useGZIP() { boolean useGZIP = WebContext.blade().environment() .getBoolean(Const.ENV_KEY_GZIP_ENABLE, false); if (!useGZIP) { return false; } String acceptEncoding = this.header(HttpConst.ACCEPT_ENCODING); if (StringKit.isEmpty(acceptEncoding)) { return false; } return acceptEncoding.contains("gzip"); } @Override public Session session() { return this.session; } @Override public boolean isSecure() { return false; } @Override public boolean isIE() { String ua = userAgent(); return ua.contains("MSIE") || ua.contains("TRIDENT"); } @Override public Map cookies() { if (!initCookie) { initCookie = true; String cookie = header(HttpConst.COOKIE_STRING); if (StringKit.isNotEmpty(cookie)) { ServerCookieDecoder.LAX.decode(cookie).forEach(this::parseCookie); } } return this.cookies; } @Override public Cookie cookieRaw(@NonNull String name) { return this.cookies().get(name); } @Override public Request cookie(@NonNull Cookie cookie) { this.cookies().put(cookie.name(), cookie); return this; } @Override public Map headers() { if (null == headers) { headers = new HashMap<>(httpHeaders.size()); Iterator> entryIterator = httpHeaders.iteratorAsString(); while (entryIterator.hasNext()) { Map.Entry next = entryIterator.next(); headers.put(next.getKey(), next.getValue()); } } return this.headers; } @Override public boolean keepAlive() { return this.keepAlive; } @Override public Map attributes() { if (null == this.attributes) { this.attributes = new HashMap<>(4); } return this.attributes; } @Override public Map fileItems() { return fileItems; } @Override public ByteBuf body() { return this.body; } @Override public boolean chunkIsEnd() { return this.isEnd; } @Override public boolean isMultipart() { return isMultipart; } public void setNettyRequest(io.netty.handler.codec.http.HttpRequest nettyRequest) { this.nettyRequest = nettyRequest; } public void appendContent(HttpContent msg) { this.contents.add(msg.retain()); if (msg instanceof LastHttpContent) { this.isEnd = true; } } public void init(String remoteAddress) { this.remoteAddress = remoteAddress.substring(1); this.keepAlive = HttpUtil.isKeepAlive(nettyRequest); this.url = nettyRequest.uri(); int pathEndPos = this.url().indexOf('?'); this.uri = pathEndPos < 0 ? this.url() : this.url().substring(0, pathEndPos); this.protocol = nettyRequest.protocolVersion().text(); this.method = nettyRequest.method().name(); String cleanUri = this.uri; if (!"/".equals(this.contextPath())) { cleanUri = PathKit.cleanPath(cleanUri.replaceFirst(this.contextPath(), "/")); this.uri = cleanUri; } this.httpHeaders = nettyRequest.headers(); if (!HttpServerHandler.PERFORMANCE) { SessionManager sessionManager = WebContext.blade().sessionManager(); if (null != sessionManager) { this.session = SESSION_HANDLER.createSession(this); } } if ("GET".equals(this.method())) { return; } try { HttpPostRequestDecoder decoder = new HttpPostRequestDecoder(HTTP_DATA_FACTORY, nettyRequest); this.isMultipart = decoder.isMultipart(); List byteBuffs = new ArrayList<>(this.contents.size()); for (HttpContent content : this.contents) { if (!isMultipart) { byteBuffs.add(content.content().copy()); } decoder.offer(content); this.readHttpDataChunkByChunk(decoder); content.release(); } if (!byteBuffs.isEmpty()) { this.body = Unpooled.copiedBuffer(byteBuffs.toArray(new ByteBuf[0])); } } catch (Exception e) { throw new HttpParseException("build decoder fail", e); } } /** * Example of reading request by chunk and getting values from chunk to chunk */ private void readHttpDataChunkByChunk(HttpPostRequestDecoder decoder) { try { while (decoder.hasNext()) { InterfaceHttpData data = decoder.next(); if (data != null) { // check if current HttpData is a FileUpload and previously set as partial if (partialContent == data) { partialContent = null; } try { // new value writeHttpData(data); } finally { data.release(); } } } // Check partial decoding for a FileUpload InterfaceHttpData data = decoder.currentPartialHttpData(); if (data != null) { if (partialContent == null) { partialContent = (HttpData) data; } } } catch (HttpPostRequestDecoder.EndOfDataDecoderException e1) { // end } } private void writeHttpData(InterfaceHttpData data) { try { InterfaceHttpData.HttpDataType dataType = data.getHttpDataType(); if (dataType == InterfaceHttpData.HttpDataType.Attribute) { parseAttribute((Attribute) data); } else if (dataType == InterfaceHttpData.HttpDataType.FileUpload) { parseFileUpload((FileUpload) data); } } catch (IOException e) { log.error("Parse request parameter error", e); } } private void parseAttribute(Attribute attribute) throws IOException { var name = attribute.getName(); var value = attribute.getValue(); List values; if (this.parameters.containsKey(name)) { values = this.parameters.get(name); values.add(value); } else { values = new ArrayList<>(); values.add(value); this.parameters.put(name, values); } } /** * Parse FileUpload to {@link FileItem}. * * @param fileUpload netty http file upload */ private void parseFileUpload(FileUpload fileUpload) throws IOException { if (!fileUpload.isCompleted()) { return; } FileItem fileItem = new FileItem(); fileItem.setName(fileUpload.getName()); fileItem.setFileName(fileUpload.getFilename()); // Upload the file is moved to the specified temporary file, // because FileUpload will be release after completion of the analysis. // tmpFile will be deleted automatically if they are used. Path tmpFile = Files.createTempFile( Paths.get(fileUpload.getFile().getParent()), "blade_", "_upload"); Path fileUploadPath = Paths.get(fileUpload.getFile().getPath()); Files.move(fileUploadPath, tmpFile, StandardCopyOption.REPLACE_EXISTING); fileItem.setFile(tmpFile.toFile()); fileItem.setPath(tmpFile.toFile().getPath()); fileItem.setContentType(fileUpload.getContentType()); fileItem.setLength(fileUpload.length()); fileItems.put(fileItem.getName(), fileItem); } /** * Parse netty cookie to {@link Cookie}. * * @param nettyCookie netty raw cookie instance */ private void parseCookie(io.netty.handler.codec.http.cookie.Cookie nettyCookie) { var cookie = new Cookie(); cookie.name(nettyCookie.name()); cookie.value(nettyCookie.value()); cookie.httpOnly(nettyCookie.isHttpOnly()); cookie.path(nettyCookie.path()); cookie.domain(nettyCookie.domain()); cookie.maxAge(nettyCookie.maxAge()); this.cookies.put(cookie.name(), cookie); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy