HttpRequest.path优化

This commit is contained in:
redkale
2023-11-23 15:14:07 +08:00
parent 0bb91186a8
commit 05e3046af8
23 changed files with 379 additions and 122 deletions

View File

@@ -72,8 +72,8 @@ public final class ApiDocCommand {
}
List<Map> serverList = new ArrayList<>();
Field __prefix = HttpServlet.class.getDeclaredField("_prefix");
__prefix.setAccessible(true);
Field prefixField = HttpServlet.class.getDeclaredField("_prefix");
prefixField.setAccessible(true);
Map<String, Map<String, Map<String, Object>>> typesMap = new LinkedHashMap<>();
//https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md
Map<String, Object> swaggerPathsMap = new LinkedHashMap<>();
@@ -117,7 +117,7 @@ public final class ApiDocCommand {
}
final String tag = ws.name().isEmpty() ? servlet.getClass().getSimpleName().replace("Servlet", "").toLowerCase() : ws.name();
final Map<String, Object> servletMap = new LinkedHashMap<>();
String prefix = (String) __prefix.get(servlet);
String prefix = (String) prefixField.get(servlet);
String[] urlregs = ws.value();
if (prefix != null && !prefix.isEmpty()) {
for (int i = 0; i < urlregs.length; i++) {
@@ -214,7 +214,7 @@ public final class ApiDocCommand {
// typesMap.put(rtype.getName(), typeMap);
// }
mappingMap.put("results", results);
boolean hasbodyparam = false;
boolean hasBodyParam = false;
Map<String, Object> swaggerRequestBody = new LinkedHashMap<>();
for (HttpParam param : method.getAnnotationsByType(HttpParam.class)) {
final Map<String, Object> oldapisParamMap = new LinkedHashMap<>();
@@ -262,7 +262,7 @@ public final class ApiDocCommand {
}
}
if (param.style() == HttpParam.HttpParameterStyle.BODY) {
hasbodyparam = true;
hasBodyParam = true;
}
if (ptype.isPrimitive() || ptype == String.class) {
continue;
@@ -354,7 +354,7 @@ public final class ApiDocCommand {
String m = action.methods() == null || action.methods().length == 0 ? null : action.methods()[0].toLowerCase();
if (m == null) {
m = hasbodyparam || TYPE_RETRESULT_STRING.equals(resultType) || TYPE_RETRESULT_INTEGER.equals(resultType)
m = hasBodyParam || TYPE_RETRESULT_STRING.equals(resultType) || TYPE_RETRESULT_INTEGER.equals(resultType)
|| TYPE_RETRESULT_LONG.equals(resultType) || action.name().contains("create") || action.name().contains("insert")
|| action.name().contains("update") || action.name().contains("delete") || action.name().contains("send") ? "post" : "get";
}

View File

@@ -71,7 +71,7 @@ public class LoggingFileHandler extends LoggingBaseHandler {
}
}
protected final LinkedBlockingQueue<LogRecord> logqueue = new LinkedBlockingQueue();
protected final LinkedBlockingQueue<LogRecord> logQueue = new LinkedBlockingQueue();
protected String pattern;
@@ -83,9 +83,9 @@ public class LoggingFileHandler extends LoggingBaseHandler {
private int limit; //文件大小限制
private final AtomicInteger logindex = new AtomicInteger();
private final AtomicInteger logIndex = new AtomicInteger();
private final AtomicInteger logunusualindex = new AtomicInteger();
private final AtomicInteger logUnusualIndex = new AtomicInteger();
private int count = 1; //文件限制
@@ -93,19 +93,19 @@ public class LoggingFileHandler extends LoggingBaseHandler {
protected boolean append;
protected Pattern denyregx;
protected Pattern denyRegx;
private final AtomicLong logLength = new AtomicLong();
private final AtomicLong logUnusualLength = new AtomicLong();
private File logfile;
private File logFile;
private File logunusualfile;
private File logUnusualFile;
private OutputStream logstream;
private OutputStream logStream;
private OutputStream logunusualstream;
private OutputStream logUnusualStream;
public LoggingFileHandler() {
updateTomorrow();
@@ -122,7 +122,7 @@ public class LoggingFileHandler extends LoggingBaseHandler {
cal.add(Calendar.DAY_OF_YEAR, 1);
long t = cal.getTimeInMillis();
if (this.tomorrow != t) {
logindex.set(0);
logIndex.set(0);
}
this.tomorrow = t;
}
@@ -139,68 +139,68 @@ public class LoggingFileHandler extends LoggingBaseHandler {
public void run() {
while (true) {
try {
LogRecord log = logqueue.take();
LogRecord log = logQueue.take();
final boolean bigger = (limit > 0 && limit <= logLength.get());
final boolean changeday = tomorrow <= log.getMillis();
if (bigger || changeday) {
updateTomorrow();
if (logstream != null) {
logstream.close();
if (logStream != null) {
logStream.close();
if (bigger) {
for (int i = Math.min(count - 2, logindex.get() - 1); i > 0; i--) {
File greater = new File(logfile.getPath() + "." + i);
for (int i = Math.min(count - 2, logIndex.get() - 1); i > 0; i--) {
File greater = new File(logFile.getPath() + "." + i);
if (greater.exists()) {
Files.move(greater.toPath(), new File(logfile.getPath() + "." + (i + 1)).toPath(), REPLACE_EXISTING, ATOMIC_MOVE);
Files.move(greater.toPath(), new File(logFile.getPath() + "." + (i + 1)).toPath(), REPLACE_EXISTING, ATOMIC_MOVE);
}
}
Files.move(logfile.toPath(), new File(logfile.getPath() + ".1").toPath(), REPLACE_EXISTING, ATOMIC_MOVE);
Files.move(logFile.toPath(), new File(logFile.getPath() + ".1").toPath(), REPLACE_EXISTING, ATOMIC_MOVE);
} else {
if (logfile.exists() && logfile.length() < 1) {
Files.delete(logfile.toPath());
if (logFile.exists() && logFile.length() < 1) {
Files.delete(logFile.toPath());
}
}
logstream = null;
logStream = null;
}
}
if (unusual != null && changeday && logunusualstream != null) {
logunusualstream.close();
if (unusual != null && changeday && logUnusualStream != null) {
logUnusualStream.close();
if (limit > 0 && limit <= logUnusualLength.get()) {
for (int i = Math.min(count - 2, logunusualindex.get() - 1); i > 0; i--) {
File greater = new File(logunusualfile.getPath() + "." + i);
for (int i = Math.min(count - 2, logUnusualIndex.get() - 1); i > 0; i--) {
File greater = new File(logUnusualFile.getPath() + "." + i);
if (greater.exists()) {
Files.move(greater.toPath(), new File(logunusualfile.getPath() + "." + (i + 1)).toPath(), REPLACE_EXISTING, ATOMIC_MOVE);
Files.move(greater.toPath(), new File(logUnusualFile.getPath() + "." + (i + 1)).toPath(), REPLACE_EXISTING, ATOMIC_MOVE);
}
}
Files.move(logunusualfile.toPath(), new File(logunusualfile.getPath() + ".1").toPath(), REPLACE_EXISTING, ATOMIC_MOVE);
Files.move(logUnusualFile.toPath(), new File(logUnusualFile.getPath() + ".1").toPath(), REPLACE_EXISTING, ATOMIC_MOVE);
} else {
if (logunusualfile.exists() && logunusualfile.length() < 1) {
Files.delete(logunusualfile.toPath());
if (logUnusualFile.exists() && logUnusualFile.length() < 1) {
Files.delete(logUnusualFile.toPath());
}
}
logunusualstream = null;
logUnusualStream = null;
}
if (logstream == null) {
logindex.incrementAndGet();
logfile = new File(patternDateFormat == null ? pattern : Times.formatTime(patternDateFormat, -1, System.currentTimeMillis()));
logfile.getParentFile().mkdirs();
logLength.set(logfile.length());
logstream = new FileOutputStream(logfile, append);
if (logStream == null) {
logIndex.incrementAndGet();
logFile = new File(patternDateFormat == null ? pattern : Times.formatTime(patternDateFormat, -1, System.currentTimeMillis()));
logFile.getParentFile().mkdirs();
logLength.set(logFile.length());
logStream = new FileOutputStream(logFile, append);
}
if (unusual != null && logunusualstream == null) {
logunusualindex.incrementAndGet();
logunusualfile = new File(unusualDateFormat == null ? unusual : Times.formatTime(unusualDateFormat, -1, System.currentTimeMillis()));
logunusualfile.getParentFile().mkdirs();
logUnusualLength.set(logunusualfile.length());
logunusualstream = new FileOutputStream(logunusualfile, append);
if (unusual != null && logUnusualStream == null) {
logUnusualIndex.incrementAndGet();
logUnusualFile = new File(unusualDateFormat == null ? unusual : Times.formatTime(unusualDateFormat, -1, System.currentTimeMillis()));
logUnusualFile.getParentFile().mkdirs();
logUnusualLength.set(logUnusualFile.length());
logUnusualStream = new FileOutputStream(logUnusualFile, append);
}
//----------------------写日志-------------------------
String message = getFormatter().format(log);
String encoding = getEncoding();
byte[] bytes = encoding == null ? message.getBytes() : message.getBytes(encoding);
logstream.write(bytes);
logStream.write(bytes);
logLength.addAndGet(bytes.length);
if (unusual != null && (log.getLevel() == Level.WARNING || log.getLevel() == Level.SEVERE)) {
logunusualstream.write(bytes);
logUnusualStream.write(bytes);
logUnusualLength.addAndGet(bytes.length);
}
} catch (Exception e) {
@@ -331,7 +331,7 @@ public class LoggingFileHandler extends LoggingBaseHandler {
String denyregxstr = manager.getProperty(cname + ".denyregx");
try {
if (denyregxstr != null && !denyregxstr.trim().isEmpty()) {
denyregx = Pattern.compile(denyregxstr);
denyRegx = Pattern.compile(denyregxstr);
}
} catch (Exception e) {
//do nothing
@@ -343,18 +343,18 @@ public class LoggingFileHandler extends LoggingBaseHandler {
if (!isLoggable(log)) {
return;
}
if (denyregx != null && denyregx.matcher(log.getMessage()).find()) {
if (denyRegx != null && denyRegx.matcher(log.getMessage()).find()) {
return;
}
fillLogRecord(log);
logqueue.offer(log);
logQueue.offer(log);
}
@Override
public void flush() {
try {
if (logstream != null) {
logstream.flush();
if (logStream != null) {
logStream.flush();
}
} catch (Exception e) {
ErrorManager err = getErrorManager();
@@ -367,8 +367,8 @@ public class LoggingFileHandler extends LoggingBaseHandler {
@Override
public void close() throws SecurityException {
try {
if (logstream != null) {
logstream.close();
if (logStream != null) {
logStream.close();
}
} catch (Exception e) {
ErrorManager err = getErrorManager();

View File

@@ -38,7 +38,7 @@ public class PrepareCompiler {
listener.preCompile(application);
}
application.start();
final boolean hasSncp = application.getNodeServers().stream().filter(v -> v instanceof NodeSncpServer).findFirst().isPresent();
final boolean hasSncp = application.getNodeServers().stream().filter(NodeSncpServer.class::isInstance).findFirst().isPresent();
final ClassFilter<?> entityFilter = new ClassFilter(application.getClassLoader(), Entity.class, Object.class, (Class[]) null);
final ClassFilter<?> entityFilter2 = new ClassFilter(application.getClassLoader(), javax.persistence.Entity.class, Object.class, (Class[]) null);

View File

@@ -41,8 +41,8 @@ public class HttpMessageRequest extends HttpRequest {
}
@Override
public HttpMessageRequest setPath(String path) {
this.path = path;
public HttpMessageRequest setRequestPath(String path) {
this.requestPath = path;
return this;
}

View File

@@ -171,7 +171,7 @@ public class HttpMessageResponse extends HttpResponse {
@Override
public void finish(int status, String msg) {
if (status > 400) {
messageClient.logger.log(Level.WARNING, "HttpMessageResponse.finish status: " + status + ", uri: " + this.request.getPath() + ", message: " + this.message);
messageClient.logger.log(Level.WARNING, "HttpMessageResponse.finish status: " + status + ", uri: " + this.request.getRequestPath() + ", message: " + this.message);
} else if (messageClient.logger.isLoggable(Level.FINEST)) {
messageClient.logger.log(Level.FINEST, "HttpMessageResponse.finish status: " + status);
}

View File

@@ -42,6 +42,7 @@ public abstract class ClientCodec<R extends ClientRequest, P extends ClientResul
this.connection = connection;
}
//buffer之后会clear
public abstract void decodeMessages(ByteBuffer buffer, ByteArray array);
public ClientCodec<R, P> withMessageListener(ClientMessageListener listener) {

View File

@@ -310,7 +310,7 @@ public class HttpDispatcherServlet extends DispatcherServlet<String, HttpContext
@Override
public void execute(HttpRequest request, HttpResponse response) throws IOException {
try {
final String uri = request.getPath();
final String uri = request.getRequestPath();
HttpServlet servlet;
if (response.isAutoOptions() && HttpRequest.METHOD_OPTIONS.equals(request.getMethod())) {
response.finish(200, null);

View File

@@ -27,7 +27,7 @@ public abstract class HttpFilter extends Filter<HttpContext, HttpRequest, HttpRe
}
protected void setPath(HttpRequest request, String path) {
request.setPath(path);
request.setRequestPath(path);
}
protected void setRemoteAddr(HttpRequest request, String remoteAddr) {

View File

@@ -130,6 +130,14 @@ public class HttpHeaders implements RestHeaders, Serializable {
return this.map != null && this.map.containsKey(name);
}
@Override
public boolean containsIgnoreCase(String name) {
if (this.map == null || name == null) {
return false;
}
return !this.map.keySet().stream().filter(name::equalsIgnoreCase).findFirst().isEmpty();
}
public HttpHeaders addAll(HttpHeaders header) {
if (header.map != null) {
if (this.map == null) {

View File

@@ -20,6 +20,7 @@ import org.redkale.convert.json.JsonConvert;
import org.redkale.net.Request;
import org.redkale.util.*;
import static org.redkale.util.Utility.isEmpty;
import static org.redkale.util.Utility.isNotEmpty;
/**
* Http请求包 与javax.servlet.http.HttpServletRequest 基本类似。 <br>
@@ -132,7 +133,7 @@ public class HttpRequest extends Request<HttpContext> {
protected String protocol;
protected String path;
protected String requestPath;
protected byte[] queryBytes;
@@ -223,13 +224,9 @@ public class HttpRequest extends Request<HttpContext> {
this.contentType = req.getContentType();
this.remoteAddr = req.getRemoteAddr();
this.locale = req.getLocale();
if (needPath) {
this.path = req.requestPath();
} else {
this.path = req.getPath();
}
this.requestPath = needPath ? req.requestPath() : req.getPath();
this.method = req.getMethod();
if (req.getSessionid() != null && !req.getSessionid().isEmpty()) {
if (isNotEmpty(req.getSessionid())) {
this.cookies = new HttpCookie[]{new HttpCookie(SESSIONID_NAME, req.getSessionid())};
}
}
@@ -255,8 +252,8 @@ public class HttpRequest extends Request<HttpContext> {
req.setContentType(getContentType());
req.setContextPath(prefixPath);
req.setMethod(this.method);
String path0 = this.path;
if (prefixPath != null && !prefixPath.isEmpty() && path0.startsWith(prefixPath)) {
String path0 = this.requestPath;
if (isNotEmpty(prefixPath) && path0.startsWith(prefixPath)) {
path0 = path0.substring(prefixPath.length());
}
req.setPath(path0);
@@ -565,7 +562,7 @@ public class HttpRequest extends Request<HttpContext> {
}
//读uri
if (this.path == null) {
if (this.requestPath == null) {
int qst = -1;//?的位置
boolean decodeable = false;
boolean latin1 = true;
@@ -589,7 +586,7 @@ public class HttpRequest extends Request<HttpContext> {
}
size = bytes.length();
if (qst > 0) { //带?参数
this.path = decodeable ? toDecodeString(bytes, 0, qst, charset) : context.loadUriPath(bytes, qst, latin1, charset);// bytes.toString(latin1, 0, qst, charset);
this.requestPath = decodeable ? toDecodeString(bytes, 0, qst, charset) : context.loadUriPath(bytes, qst, latin1, charset);// bytes.toString(latin1, 0, qst, charset);
int qlen = size - qst - 1;
this.queryBytes = bytes.getBytes(qst + 1, qlen);
this.lastPathString = null;
@@ -601,20 +598,20 @@ public class HttpRequest extends Request<HttpContext> {
}
} else {
if (decodeable) { //需要转义
this.path = toDecodeString(bytes, 0, bytes.length(), charset);
this.requestPath = toDecodeString(bytes, 0, bytes.length(), charset);
this.lastPathString = null;
this.lastPathBytes = null;
} else if (context.lazyHeaders) {
byte[] lastURIBytes = lastPathBytes;
if (lastURIBytes != null && lastURIBytes.length == size && bytes.deepEquals(lastURIBytes)) {
this.path = this.lastPathString;
this.requestPath = this.lastPathString;
} else {
this.path = context.loadUriPath(bytes, latin1, charset);// bytes.toString(latin1, charset);
this.lastPathString = this.path;
this.requestPath = context.loadUriPath(bytes, latin1, charset);// bytes.toString(latin1, charset);
this.lastPathString = this.requestPath;
this.lastPathBytes = bytes.getBytes();
}
} else {
this.path = context.loadUriPath(bytes, latin1, charset); //bytes.toString(latin1, charset);
this.requestPath = context.loadUriPath(bytes, latin1, charset); //bytes.toString(latin1, charset);
this.lastPathString = null;
this.lastPathBytes = null;
}
@@ -984,7 +981,7 @@ public class HttpRequest extends Request<HttpContext> {
this.method = null;
this.getmethod = false;
this.protocol = null;
this.path = null;
this.requestPath = null;
this.queryBytes = null;
this.boundary = false;
this.bodyParsed = false;
@@ -1045,8 +1042,8 @@ public class HttpRequest extends Request<HttpContext> {
return this;
}
protected HttpRequest setPath(String path) {
this.path = path;
protected HttpRequest setRequestPath(String path) {
this.requestPath = path;
return this;
}
@@ -1534,7 +1531,7 @@ public class HttpRequest extends Request<HttpContext> {
@Override
public String toString() {
parseBody();
return this.getClass().getSimpleName() + "{\r\n method: " + this.method + ", \r\n path: " + this.path
return this.getClass().getSimpleName() + "{\r\n method: " + this.method + ", \r\n path: " + this.requestPath
+ (this.reqConvertType != null ? (", \r\n reqConvertType: " + this.reqConvertType) : "")
+ (this.respConvertType != null ? (", \r\n respConvertType: " + this.respConvertType) : "")
+ (this.currentUserid != CURRUSERID_NIL ? (", \r\n currentUserid: " + (this.currentUserid == CURRUSERID_NIL ? null : this.currentUserid)) : "")
@@ -1781,8 +1778,8 @@ public class HttpRequest extends Request<HttpContext> {
*
* @return 请求的URL
*/
public String getPath() {
return path;
public String getRequestPath() {
return requestPath;
}
/**
@@ -1795,16 +1792,16 @@ public class HttpRequest extends Request<HttpContext> {
}
/**
* 截取getPath最后的一个/后面的部分
* 截取getRequestPath最后的一个/后面的部分
*
* @return String
*/
@ConvertDisabled
public String getPathLastParam() {
if (path == null) {
if (requestPath == null) {
return "";
}
return path.substring(path.lastIndexOf('/') + 1);
return requestPath.substring(requestPath.lastIndexOf('/') + 1);
}
/**
@@ -1969,10 +1966,10 @@ public class HttpRequest extends Request<HttpContext> {
* @return String[]
*/
public String[] getPathParams(String prefix) {
if (path == null || prefix == null) {
if (requestPath == null || prefix == null) {
return new String[0];
}
return path.substring(path.indexOf(prefix) + prefix.length() + (prefix.endsWith("/") ? 0 : 1)).split("/");
return requestPath.substring(requestPath.indexOf(prefix) + prefix.length() + (prefix.endsWith("/") ? 0 : 1)).split("/");
}
/**
@@ -1986,14 +1983,14 @@ public class HttpRequest extends Request<HttpContext> {
* @return prefix截断后的值
*/
public String getPathParam(String prefix, String defvalue) {
if (path == null || prefix == null || prefix.isEmpty()) {
if (requestPath == null || prefix == null || prefix.isEmpty()) {
return defvalue;
}
int pos = path.indexOf(prefix);
int pos = requestPath.indexOf(prefix);
if (pos < 0) {
return defvalue;
}
String sub = path.substring(pos + prefix.length());
String sub = requestPath.substring(pos + prefix.length());
pos = sub.indexOf('/');
return pos < 0 ? sub : sub.substring(0, pos);
}

View File

@@ -212,7 +212,7 @@ public class HttpResourceServlet extends HttpServlet {
@Override
public void execute(HttpRequest request, HttpResponse response) throws IOException {
String uri = request.getPath();
String uri = request.getRequestPath();
if (uri.contains("../")) {
if (logger.isLoggable(Level.FINEST)) {
logger.log(Level.FINEST, "Not found resource (404) be " + uri + ", request = " + request);
@@ -254,7 +254,7 @@ public class HttpResourceServlet extends HttpServlet {
}
if (entry == null) {
if (logger.isLoggable(Level.FINER)) {
logger.log(Level.FINER, "Not found resource (404), url = " + request.getPath());
logger.log(Level.FINER, "Not found resource (404), url = " + request.getRequestPath());
}
finish404(request, response);
} else {

View File

@@ -66,7 +66,7 @@ public class HttpServlet extends Servlet<HttpContext, HttpRequest, HttpResponse>
}
}
if (entry.cacheSeconds > 0) {//有缓存设置
CacheEntry ce = entry.modeOneCache ? entry.oneCache : entry.cache.get(request.getPath());
CacheEntry ce = entry.modeOneCache ? entry.oneCache : entry.cache.get(request.getRequestPath());
if (ce != null && ce.time + entry.cacheSeconds * 1000 > System.currentTimeMillis()) { //缓存有效
response.setStatus(ce.status);
response.setContentType(ce.contentType);
@@ -125,7 +125,7 @@ public class HttpServlet extends Servlet<HttpContext, HttpRequest, HttpResponse>
return;
}
for (Map.Entry<String, ActionEntry> en : mappings) {
if (request.getPath().startsWith(en.getKey())) {
if (request.getRequestPath().startsWith(en.getKey())) {
ActionEntry entry = en.getValue();
if (!entry.checkMethod(request.getMethod())) {
//response.finishJson(new RetResult(RET_METHOD_ERROR, "Method(" + request.getMethod() + ") Error"));
@@ -146,7 +146,7 @@ public class HttpServlet extends Servlet<HttpContext, HttpRequest, HttpResponse>
}
}
finish404(request, response);
//throw new IOException(this.getClass().getName() + " not found method for URI(" + request.getPath() + ")");
//throw new IOException(this.getClass().getName() + " not found method for URI(" + request.getRequestPath() + ")");
}
};
@@ -411,7 +411,7 @@ public class HttpServlet extends Servlet<HttpContext, HttpRequest, HttpResponse>
return;
}
CacheEntry ce = new CacheEntry(response.getStatus(), response.getContentType(), content);
cache.put(response.getRequest().getPath(), ce);
cache.put(response.getRequest().getRequestPath(), ce);
} : null;
} else { //单一url
this.modeOneCache = true;

View File

@@ -42,6 +42,8 @@ public class HttpSimpleClient extends Client<HttpSimpleConnection, HttpSimpleReq
static final byte[] header_bytes_connclose = ("Connection: close\r\n").getBytes(StandardCharsets.UTF_8);
static final byte[] header_bytes_connalive = ("Connection: keep-alive\r\n").getBytes(StandardCharsets.UTF_8);
protected final AsyncGroup asyncGroup;
protected ExecutorService workExecutor;
@@ -245,13 +247,13 @@ public class HttpSimpleClient extends Client<HttpSimpleConnection, HttpSimpleReq
array.put(("Host: " + uri.getHost() + "\r\n").getBytes(StandardCharsets.UTF_8));
array.put(("Content-Length: " + (body == null ? 0 : body.length) + "\r\n").getBytes(StandardCharsets.UTF_8));
if (headers == null || !headers.contains("User-Agent")) {
if (headers == null || !headers.containsIgnoreCase("User-Agent")) {
array.put(header_bytes_useragent);
}
if (headers == null || !headers.contains("Connection")) {
if (headers == null || !headers.containsIgnoreCase("Connection")) {
array.put(header_bytes_connclose);
}
if (headers == null || !headers.contains(Rest.REST_HEADER_TRACEID)) {
if (headers == null || !headers.containsIgnoreCase(Rest.REST_HEADER_TRACEID)) {
array.put((Rest.REST_HEADER_TRACEID + ": " + traceid + "\r\n").getBytes(StandardCharsets.UTF_8));
}
if (headers != null) {

View File

@@ -4,7 +4,9 @@
package org.redkale.net.http;
import java.nio.ByteBuffer;
import java.util.logging.Logger;
import org.redkale.net.client.ClientCodec;
import static org.redkale.net.http.HttpRequest.*;
import org.redkale.util.ByteArray;
/**
@@ -13,13 +15,226 @@ import org.redkale.util.ByteArray;
*/
class HttpSimpleCodec extends ClientCodec<HttpSimpleRequest, HttpSimpleResult> {
protected static final Logger logger = Logger.getLogger(HttpSimpleCodec.class.getSimpleName());
private ByteArray recyclableArray;
private ByteArray halfBytes;
private HttpSimpleResult lastResult = null;
public HttpSimpleCodec(HttpSimpleConnection connection) {
super(connection);
}
@Override
public void decodeMessages(ByteBuffer buffer, ByteArray array) {
protected HttpSimpleResult pollResult(HttpSimpleRequest request) {
return new HttpSimpleResult();
}
protected void offerResult(HttpSimpleResult rs) {
//do nothing
}
private ByteArray pollArray(ByteArray array) {
if (recyclableArray == null) {
recyclableArray = new ByteArray();
}
recyclableArray.clear();
if (array != null) {
recyclableArray.put(array);
}
return recyclableArray;
}
@Override
public void decodeMessages(final ByteBuffer realBuf, final ByteArray array) {
int rs;
HttpSimpleResult result = this.lastResult;
final ByteBuffer buffer = realBuf;
while (buffer.hasRemaining()) {
if (result == null) {
result = new HttpSimpleResult();
this.lastResult = result;
}
array.clear();
if (this.halfBytes != null) {
array.put(this.halfBytes);
this.halfBytes = null;
}
if (result.readState == READ_STATE_ROUTE) {
rs = readStatusLine(result, buffer, array);
if (rs > 0) { //数据不全
this.halfBytes = pollArray(array);
return;
} else if (rs < 0) { //数据异常
occurError(null, new HttpException("http data not valid"));
return;
}
result.readState = READ_STATE_HEADER;
}
if (result.readState == READ_STATE_HEADER) {
rs = readHeaderLines(result, buffer, array);
if (rs > 0) { //数据不全
this.halfBytes = pollArray(array);
return;
} else if (rs < 0) { //数据异常
occurError(null, new HttpException("http data not valid"));
return;
}
result.readState = READ_STATE_BODY;
}
if (result.readState == READ_STATE_BODY) {
rs = readBody(result, buffer, array);
if (rs > 0) { //数据不全
this.halfBytes = pollArray(array);
return;
} else if (rs < 0) { //数据异常
occurError(null, new HttpException("http data not valid"));
return;
}
result.readState = READ_STATE_END;
}
addMessage(nextRequest(), result);
lastResult = null;
}
}
//解析 HTTP/1.1 200 OK
private int readStatusLine(final HttpSimpleResult result, final ByteBuffer buffer, final ByteArray array) {
int remain = buffer.remaining();
if (array.length() > 0 && array.getLastByte() == '\r') { //array存在半截数据
if (buffer.get() != '\n') {
return -1;
}
} else {
for (;;) {
if (remain-- < 1) {
return 1;
}
byte b = buffer.get();
if (b == '\r') {
if (remain-- < 1) {
array.put((byte) '\r');
return 1;
}
if (buffer.get() != '\n') {
return -1;
}
break;
}
array.put(b);
}
}
String value = array.toString(null);
int pos = value.indexOf(' ');
result.setStatus(Integer.decode(value.substring(pos + 1, value.indexOf(" ", pos + 2))));
array.clear();
return 0;
}
//解析Header Connection: keep-alive
//返回0表示解析完整非0表示还需继续读数据
private int readHeaderLines(final HttpSimpleResult result, final ByteBuffer buffer, final ByteArray array) {
int remain = buffer.remaining();
for (;;) {
array.clear();
if (remain-- < 2) {
if (remain == 1) {
array.put(buffer.get());
return 1;
}
return 1;
}
remain--;
byte b1 = buffer.get();
byte b2 = buffer.get();
if (b1 == '\r' && b2 == '\n') {
return 0;
}
boolean latin1 = true;
if (latin1 && (b1 < 0x20 || b1 >= 0x80)) {
latin1 = false;
}
if (latin1 && (b2 < 0x20 || b2 >= 0x80)) {
latin1 = false;
}
array.put(b1, b2);
for (;;) { // name
if (remain-- < 1) {
buffer.clear();
buffer.put(array.content(), 0, array.length());
return 1;
}
byte b = buffer.get();
if (b == ':') {
break;
} else if (latin1 && (b < 0x20 || b >= 0x80)) {
latin1 = false;
}
array.put(b);
}
String name = parseHeaderName(latin1, array, null);
array.clear();
boolean first = true;
int space = 0;
for (;;) { // value
if (remain-- < 1) {
buffer.clear();
buffer.put(name.getBytes());
buffer.put((byte) ':');
if (space == 1) {
buffer.put((byte) ' ');
} else if (space > 0) {
for (int i = 0; i < space; i++) buffer.put((byte) ' ');
}
buffer.put(array.content(), 0, array.length());
return 1;
}
byte b = buffer.get();
if (b == '\r') {
if (remain-- < 1) {
buffer.clear();
buffer.put(name.getBytes());
buffer.put((byte) ':');
if (space == 1) {
buffer.put((byte) ' ');
} else if (space > 0) {
for (int i = 0; i < space; i++) buffer.put((byte) ' ');
}
buffer.put(array.content(), 0, array.length());
buffer.put((byte) '\r');
return 1;
}
if (buffer.get() != '\n') {
return -1;
}
break;
}
if (first) {
if (b <= ' ') {
space++;
continue;
}
first = false;
}
array.put(b);
}
String value;
switch (name) {
case "Content-Length":
case "content-length":
value = array.toString(true, null);
result.contentLength = Integer.decode(value);
result.header(name, value);
break;
default:
value = array.toString(null);
result.header(name, value);
}
}
}
private int readBody(final HttpSimpleResult result, final ByteBuffer buffer, final ByteArray array) {
return 0;
}
}

View File

@@ -15,6 +15,7 @@ import org.redkale.convert.*;
import org.redkale.convert.json.JsonConvert;
import org.redkale.net.client.ClientConnection;
import org.redkale.net.client.ClientRequest;
import static org.redkale.net.http.HttpSimpleClient.*;
import org.redkale.util.ByteArray;
import org.redkale.util.RedkaleException;
import org.redkale.util.Traces;
@@ -109,13 +110,19 @@ public class HttpSimpleRequest extends ClientRequest implements java.io.Serializ
@Override
public void writeTo(ClientConnection conn, ByteArray array) {
array.put((method.toUpperCase() + " " + path + " HTTP/1.1\r\n"
+ Rest.REST_HEADER_TRACEID + ": " + traceid + "\r\n"
+ "Content-Length: " + (body == null ? 0 : body.length) + "\r\n").getBytes(StandardCharsets.UTF_8));
array.put((method.toUpperCase() + " " + requestPath() + " HTTP/1.1\r\n").getBytes(StandardCharsets.UTF_8));
if (traceid != null && !containsHeaderIgnoreCase(Rest.REST_HEADER_TRACEID)) {
array.put((Rest.REST_HEADER_TRACEID + ": " + traceid + "\r\n").getBytes(StandardCharsets.UTF_8));
}
if (!containsHeaderIgnoreCase("User-Agent")) {
array.put(header_bytes_useragent);
}
if (!containsHeaderIgnoreCase("Connection")) {
array.put(header_bytes_connalive);
}
array.put(contentLengthBytes());
if (headers != null) {
headers.forEach((k, v) -> {
array.put((k + ": " + v + "\r\n").getBytes(StandardCharsets.UTF_8));
});
headers.forEach((k, v) -> array.put((k + ": " + v + "\r\n").getBytes(StandardCharsets.UTF_8)));
}
array.put((byte) '\r', (byte) '\n');
if (body != null) {
@@ -123,6 +130,18 @@ public class HttpSimpleRequest extends ClientRequest implements java.io.Serializ
}
}
protected boolean containsHeaderIgnoreCase(String name) {
return headers != null && headers.containsIgnoreCase(name);
}
protected byte[] contentLengthBytes() {
int len = body == null ? 0 : body.length;
if (len < contentLengthArray.length) {
return contentLengthArray[len];
}
return ("Content-Length: " + len + "\r\n").getBytes(StandardCharsets.UTF_8);
}
@Nullable
@ConvertDisabled
public String getParametersToString() {
@@ -493,4 +512,11 @@ public class HttpSimpleRequest extends ClientRequest implements java.io.Serializ
return JsonConvert.root().convertTo(this);
}
private static final byte[][] contentLengthArray = new byte[1000][];
static {
for (int i = 0; i < contentLengthArray.length; i++) {
contentLengthArray[i] = ("Content-Length: " + i + "\r\n").getBytes();
}
}
}

View File

@@ -4,6 +4,7 @@
package org.redkale.net.http;
import org.redkale.net.client.ClientResult;
import static org.redkale.net.http.HttpSimpleClient.ClientReadCompletionHandler.READ_STATE_ROUTE;
/**
*
@@ -17,6 +18,14 @@ import org.redkale.net.client.ClientResult;
*/
class HttpSimpleResult<T> extends HttpResult<T> implements ClientResult {
int readState = READ_STATE_ROUTE;
int contentLength = -1;
byte[] headerBytes;
boolean headerParsed = false;
@Override
public boolean isKeepAlive() {
return true;

View File

@@ -1386,7 +1386,7 @@ public final class Rest {
} else if (annlocale != null) { //HttpRequest.getLocale
} else if (annbody != null) { //HttpRequest.getBodyUTF8 / HttpRequest.getBody
} else if (annfile != null) { //MultiContext.partsFirstBytes / HttpRequest.partsFirstFile / HttpRequest.partsFiles
} else if (annpath != null) { //HttpRequest.getPath
} else if (annpath != null) { //HttpRequest.getRequestPath
} else if (annuserid != null) { //HttpRequest.currentUserid
} else if (pname != null && pname.charAt(0) == '#') { //从request.getPathParam 中去参数
} else if ("#".equals(pname)) { //从request.getRequstURI 中取参数
@@ -2590,9 +2590,9 @@ public final class Rest {
mv.visitVarInsn(ALOAD, 4);
mv.visitVarInsn(ASTORE, maxLocals);
varInsns.add(new int[]{ALOAD, maxLocals});
} else if (annpath != null) { //HttpRequest.getPath
} else if (annpath != null) { //HttpRequest.getRequestPath
mv.visitVarInsn(ALOAD, 1);
mv.visitMethodInsn(INVOKEVIRTUAL, reqInternalName, "getPath", "()Ljava/lang/String;", false);
mv.visitMethodInsn(INVOKEVIRTUAL, reqInternalName, "getRequestPath", "()Ljava/lang/String;", false);
mv.visitVarInsn(ASTORE, maxLocals);
varInsns.add(new int[]{ALOAD, maxLocals});
} else if (userid != null) { //HttpRequest.currentUserid

View File

@@ -34,5 +34,7 @@ public interface RestHeaders {
public boolean contains(String name);
public boolean containsIgnoreCase(String name);
public Map<String, Serializable> map();
}

View File

@@ -12,7 +12,7 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* 只能注解于Service类的方法的String参数或参数内的String字段
* <p>
* 用于获取HTTP请求URL HttpRequest.getPath
* 用于获取HTTP请求URL HttpRequest.getRequestPath
* <p>
* 详情见: https://redkale.org
*

View File

@@ -22,8 +22,6 @@ public class SncpClientCodec extends ClientCodec<SncpClientRequest, SncpClientRe
protected static final Logger logger = Logger.getLogger(SncpClientCodec.class.getSimpleName());
private final ObjectPool<SncpClientResult> resultPool = ObjectPool.createUnsafePool(256, t -> new SncpClientResult(), SncpClientResult::prepare, SncpClientResult::recycle);
private ByteArray recyclableArray;
private ByteArray halfBodyBytes;
@@ -41,12 +39,11 @@ public class SncpClientCodec extends ClientCodec<SncpClientRequest, SncpClientRe
}
protected SncpClientResult pollResult(SncpClientRequest request) {
SncpClientResult rs = resultPool.get();
return rs;
return new SncpClientResult();
}
protected void offerResult(SncpClientResult rs) {
resultPool.accept(rs);
//do nothing
}
protected ByteArray pollArray() {

View File

@@ -25,9 +25,9 @@ public class SncpClientResult implements ClientResult {
private byte[] bodyContent;
protected void prepare() {
//do nothing
}
// protected void prepare() {
// //do nothing
// }
protected boolean recycle() {
this.header = null;

View File

@@ -17,7 +17,7 @@ public class UploadTestServlet extends HttpServlet {
@Override
public void execute(HttpRequest request, HttpResponse response) throws IOException {
if (request.getPath().contains("/uploadtest/send")) {
if (request.getRequestPath().contains("/uploadtest/send")) {
send(request, response);
} else {
form(request, response);

View File

@@ -53,7 +53,7 @@ public class VideoWebSocketServlet extends WebSocketServlet {
@Override
public CompletableFuture<String> onOpen(final HttpRequest request) {
String uri = request.getPath();
String uri = request.getRequestPath();
int pos = uri.indexOf("/listen/");
uri = uri.substring(pos + "/listen/".length());
this.repeat = sessions.get(uri) != null;