Files
redkale/src/com/wentch/redkale/net/http/HttpRequest.java
地平线 151273cce3
2015-04-14 09:23:35 +08:00

474 lines
15 KiB
Java

/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package com.wentch.redkale.net.http;
import com.wentch.redkale.convert.json.*;
import com.wentch.redkale.net.*;
import com.wentch.redkale.util.AnyValue.DefaultAnyValue;
import java.io.*;
import java.net.*;
import java.nio.*;
import java.nio.channels.*;
import java.nio.charset.*;
/**
*
* @author zhangjx
*/
public final class HttpRequest extends Request {
protected static final String SESSIONID_NAME = "JSESSIONID";
private static final byte[] flashRequestContent1 = "<policy-file-request/>\0".getBytes();
private static final byte[] flashRequestContent2 = "<policy-file-request/>".getBytes();
private String method;
private String protocol;
protected String requestURI;
private long contentLength = -1;
private String contentType;
private String host;
private String connection;
protected String cookiestr;
private HttpCookie[] cookies;
protected String newsessionid;
protected final JsonConvert convert;
protected final DefaultAnyValue header = new DefaultAnyValue();
protected final DefaultAnyValue params = new DefaultAnyValue();
private final ByteArray array = new ByteArray();
protected boolean flashPolicy = false;
protected boolean boundary = false;
private final String remoteAddrHeader;
protected HttpRequest(Context context, JsonFactory factory, String remoteAddrHeader) {
super(context);
this.convert = factory.getConvert();
this.remoteAddrHeader = remoteAddrHeader;
}
protected void setKeepAlive(boolean keepAlive) {
this.keepAlive = keepAlive;
}
protected boolean isKeepAlive() {
return this.keepAlive;
}
protected AsyncConnection getChannel() {
return this.channel;
}
@Override
protected int readHeader(final ByteBuffer buffer) {
if (!readLine(buffer, array)) {
if (array.equal(flashRequestContent1) || array.equal(flashRequestContent2)) { //兼容 flash socket <policy-file-request/>
this.flashPolicy = true;
return 0;
}
return -1;
}
Charset charset = this.context.getCharset();
int index = 0;
int offset = array.find(index, ' ');
if (offset <= 0) return -1;
this.method = array.toString(index, offset, charset).trim();
index = ++offset;
offset = array.find(index, ' ');
if (offset <= 0) return -1;
int off = array.find(index, '#');
if (off > 0) offset = off;
int qst = array.find(index, offset, (byte) '?');
if (qst > 0) {
this.requestURI = array.toDecodeString(index, qst - index, charset).trim();
addParameter(array, qst + 1, offset - qst - 1);
} else {
this.requestURI = array.toDecodeString(index, offset - index, charset).trim();
}
if (this.requestURI.contains("../")) return -1;
index = ++offset;
this.protocol = array.toString(index, array.count() - index, charset).trim();
while (readLine(buffer, array)) {
if (array.count() < 2) break;
index = 0;
offset = array.find(index, ':');
if (offset <= 0) return -1;
String name = array.toString(index, offset, charset).trim();
index = offset + 1;
String value = array.toString(index, array.count() - index, charset).trim();
switch (name) {
case "Content-Type":
this.contentType = value;
break;
case "Content-Length":
this.contentLength = Long.decode(value);
break;
case "Host":
this.host = value;
break;
case "Cookie":
if (this.cookiestr == null || this.cookiestr.isEmpty()) {
this.cookiestr = value;
} else {
this.cookiestr += ";" + value;
}
break;
case "Connection":
this.connection = value;
this.setKeepAlive("Keep-Alive".equalsIgnoreCase(value));
break;
default:
header.addValue(name, value);
}
}
array.clear();
if (buffer.hasRemaining()) array.add(buffer, buffer.remaining());
if (this.contentType != null && this.contentType.contains("boundary=")) {
this.boundary = true;
}
if (this.contentLength > 0 && (this.contentType == null || !this.boundary)) {
if (this.contentLength > context.getMaxbody()) return -1;
int lr = (int) this.contentLength - array.count();
return lr > 0 ? lr : 0;
}
return 0;
}
@Override
protected void readBody(ByteBuffer buffer) {
array.add(buffer, buffer.remaining());
}
@Override
protected void prepare() {
}
private void parseBody() {
if (this.boundary || array.isEmpty()) return;
addParameter(array, 0, array.count());
array.clear();
}
private void addParameter(final ByteArray array, final int offset, final int len) {
if (len < 1) return;
Charset charset = this.context.getCharset();
int limit = offset + len;
int keypos = array.find(offset, limit, '=');
int valpos = array.find(offset, limit, '&');
if (keypos <= 0 || (valpos >= 0 && valpos < keypos)) {
if (valpos > 0) addParameter(array, valpos + 1, limit - valpos - 1);
return;
}
String name = array.toDecodeString(offset, keypos - offset, charset);
++keypos;
String value = array.toDecodeString(keypos, (valpos < 0) ? (limit - keypos) : (valpos - keypos), charset);
this.params.addValue(name, value);
if (valpos >= 0) {
addParameter(array, valpos + 1, limit - valpos - 1);
}
}
private boolean readLine(ByteBuffer buffer, ByteArray bytes) {
byte lasted = '\r';
bytes.clear();
for (;;) {
if (!buffer.hasRemaining()) {
if (lasted != '\r') bytes.add(lasted);
return false;
}
byte b = buffer.get();
if (b == -1 || (lasted == '\r' && b == '\n')) break;
if (lasted != '\r') bytes.add(lasted);
lasted = b;
}
return true;
}
@Override
protected void setProperty(String name, Object value) {
super.setProperty(name, value);
}
@Override
@SuppressWarnings("unchecked")
protected <T> T getProperty(String name) {
return super.getProperty(name);
}
@Override
protected void removeProperty(String name) {
super.removeProperty(name);
}
@Override
public HttpContext getContext() {
return (HttpContext) this.context;
}
public String getRemoteAddr() {
if (remoteAddrHeader != null) {
String val = getHeader(remoteAddrHeader);
if (val != null) return val;
}
SocketAddress addr = getRemoteAddress();
if (addr == null) return "";
if (addr instanceof InetSocketAddress) return ((InetSocketAddress) addr).getAddress().getHostAddress();
return String.valueOf(addr);
}
public SocketAddress getRemoteAddress() {
return this.channel.getRemoteAddress();
}
@Override
public String toString() {
parseBody();
return this.getClass().getSimpleName() + "{method:" + this.method + ", requestURI:" + this.requestURI
+ ", contentType:" + this.contentType + ", connection:" + this.connection + ", protocol:" + this.protocol
+ ", contentLength:" + this.contentLength + ", cookiestr:" + this.cookiestr
+ ", host:" + this.host + ", params:" + this.params + ", header:" + this.header + "body:" + (array == null ? "null" : array.toString()) + "}";
}
public final MultiContext getMultiContext() {
return new MultiContext(context.getCharset(), this.getContentType(),
new BufferedInputStream(Channels.newInputStream(this.channel), Math.max(array.count(), 8192)) {
{
array.write(this.buf);
this.count = array.count();
}
});
}
@Override
protected void recycle() {
this.cookiestr = null;
this.cookies = null;
this.newsessionid = null;
this.method = null;
this.protocol = null;
this.requestURI = null;
this.contentType = null;
this.host = null;
this.connection = null;
this.contentLength = -1;
this.boundary = false;
this.flashPolicy = false;
this.header.clear();
this.params.clear();
super.recycle();
}
public String getSessionid(boolean create) {
String sessionid = getCookie(SESSIONID_NAME, null);
if (create && (sessionid == null || sessionid.isEmpty())) {
sessionid = ((HttpContext) context).createSessionid();
this.newsessionid = sessionid;
}
return sessionid;
}
public String changeSessionid() {
this.newsessionid = ((HttpContext) context).createSessionid();
return newsessionid;
}
public void invalidateSession() {
this.newsessionid = ""; //为空表示删除sessionid
}
public HttpCookie[] getCookies() {
if (this.cookies == null) this.cookies = parseCookies(this.cookiestr);
return this.cookies;
}
public String getCookie(String name) {
return getCookie(name, null);
}
public String getCookie(String name, String dfvalue) {
for (HttpCookie cookie : getCookies()) {
if (name.equals(cookie.getName())) return cookie.getValue();
}
return dfvalue;
}
private static HttpCookie[] parseCookies(String cookiestr) {
if (cookiestr == null || cookiestr.isEmpty()) return new HttpCookie[0];
String str = cookiestr.replaceAll("(^;)|(;$)", "").replaceAll(";+", ";");
if (str.isEmpty()) return new HttpCookie[0];
String[] strs = str.split(";");
HttpCookie[] cookies = new HttpCookie[strs.length];
for (int i = 0; i < strs.length; i++) {
String s = strs[i];
int pos = s.indexOf('=');
String v = (pos < 0 ? "" : s.substring(pos + 1));
if (v.indexOf('"') == 0 && v.lastIndexOf('"') == v.length() - 1) v = v.substring(1, v.length() - 1);
cookies[i] = new HttpCookie((pos < 0 ? s : s.substring(0, pos)), v);
}
return cookies;
}
public String getConnection() {
return connection;
}
public String getMethod() {
return method;
}
public String getProtocol() {
return protocol;
}
public String getHost() {
return host;
}
protected static InetSocketAddress parseSocketAddress(String host) {
if (host == null || host.isEmpty()) return null;
int pos = host.indexOf(':');
String hostname = pos < 0 ? host : host.substring(0, pos);
int port = pos < 0 ? 80 : Integer.parseInt(host.substring(pos + 1));
return new InetSocketAddress(hostname, port);
}
protected InetSocketAddress getHostSocketAddress() {
return parseSocketAddress(host);
}
/**
* 截取getRequestURI最后的一个/后面的部分
*
* @return
*/
public String getRequstURILastPath() {
if (requestURI == null) return "";
return requestURI.substring(requestURI.lastIndexOf('/') + 1);
}
public String getRequestURI() {
return requestURI;
}
public long getContentLength() {
return contentLength;
}
public String getContentType() {
return contentType;
}
//------------------------------------------------------------------------------
public String[] getHeaderNames() {
return header.getNames();
}
public String getHeader(String name) {
return header.getValue(name);
}
public <T> T getJsonHeader(Class<T> clazz, String name) {
String v = getHeader(name);
return v == null || v.isEmpty() ? null : convert.convertFrom(clazz, v);
}
public boolean getBooleanHeader(String name, boolean defaultValue) {
return header.getBoolValue(name, defaultValue);
}
public short getShortHeader(String name, short defaultValue) {
return header.getShortValue(name, defaultValue);
}
public int getIntHeader(String name, int defaultValue) {
return header.getIntValue(name, defaultValue);
}
public long getLongHeader(String name, long defaultValue) {
return header.getLongValue(name, defaultValue);
}
public float getFloatHeader(String name, float defaultValue) {
return header.getFloatValue(name, defaultValue);
}
public double getDoubleHeader(String name, double defaultValue) {
return header.getDoubleValue(name, defaultValue);
}
public String getHeader(String name, String defaultValue) {
return header.getValue(name, defaultValue);
}
//------------------------------------------------------------------------------
public String[] getParameterNames() {
parseBody();
return params.getNames();
}
public String getParameter(String name) {
parseBody();
return params.getValue(name);
}
public <T> T getJsonParameter(Class<T> clazz, String name) {
String v = getParameter(name);
return v == null || v.isEmpty() ? null : convert.convertFrom(clazz, v);
}
public boolean getBooleanParameter(String name, boolean defaultValue) {
parseBody();
return params.getBoolValue(name, defaultValue);
}
public short getShortParameter(String name, short defaultValue) {
parseBody();
return params.getShortValue(name, defaultValue);
}
public int getIntParameter(String name, int defaultValue) {
parseBody();
return params.getIntValue(name, defaultValue);
}
public long getLongParameter(String name, long defaultValue) {
parseBody();
return params.getLongValue(name, defaultValue);
}
public float getFloatParameter(String name, float defaultValue) {
parseBody();
return params.getFloatValue(name, defaultValue);
}
public double getDoubleParameter(String name, double defaultValue) {
parseBody();
return params.getDoubleValue(name, defaultValue);
}
public String getParameter(String name, String defaultValue) {
parseBody();
return params.getValue(name, defaultValue);
}
}