
io.jsync.http.impl.DefaultHttpServerRequest Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jsync.io Show documentation
Show all versions of jsync.io Show documentation
jsync.io is a non-blocking, event-driven networking framework for Java
/*
* Copyright (c) 2011-2013 The original author or authors
* ------------------------------------------------------
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Apache License v2.0 which accompanies this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* The Apache License v2.0 is available at
* http://www.opensource.org/licenses/apache2.0.php
*
* You may elect to redistribute this code under either of these licenses.
*/
package io.jsync.http.impl;
import io.jsync.Handler;
import io.jsync.MultiMap;
import io.jsync.VoidHandler;
import io.jsync.buffer.Buffer;
import io.jsync.http.*;
import io.jsync.http.HttpVersion;
import io.jsync.logging.Logger;
import io.jsync.logging.impl.LoggerFactory;
import io.jsync.net.NetSocket;
import io.netty.buffer.ByteBuf;
import io.netty.handler.codec.http.*;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.multipart.*;
import javax.net.ssl.SSLPeerUnverifiedException;
import javax.security.cert.X509Certificate;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.InetSocketAddress;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.Charset;
import java.util.List;
import java.util.Map;
/**
* @author Tim Fox
*/
public class DefaultHttpServerRequest implements HttpServerRequest {
private static final Logger log = LoggerFactory.getLogger(DefaultHttpServerRequest.class);
private final ServerConnection conn;
private final HttpRequest request;
private final HttpServerResponse response;
private HttpVersion version;
private String method;
private String uri;
private String path;
private String query;
private Handler dataHandler;
private Handler exceptionHandler;
//Cache this for performance
private MultiMap params;
private MultiMap headers;
private URI absoluteURI;
private NetSocket netSocket;
private Handler uploadHandler;
private Handler endHandler;
private MultiMap attributes;
private HttpPostRequestDecoder decoder;
DefaultHttpServerRequest(final ServerConnection conn,
final HttpRequest request,
final HttpServerResponse response) {
this.conn = conn;
this.request = request;
this.response = response;
}
@Override
public HttpVersion version() {
if (version == null) {
io.netty.handler.codec.http.HttpVersion nettyVersion = request.getProtocolVersion();
if (nettyVersion == io.netty.handler.codec.http.HttpVersion.HTTP_1_0) {
version = HttpVersion.HTTP_1_0;
} else if (nettyVersion == io.netty.handler.codec.http.HttpVersion.HTTP_1_1) {
version = HttpVersion.HTTP_1_1;
} else {
throw new IllegalStateException("Unsupported HTTP version: " + nettyVersion);
}
}
return version;
}
@Override
public String method() {
if (method == null) {
method = request.getMethod().toString();
}
return method;
}
@Override
public String uri() {
if (uri == null) {
uri = request.getUri();
}
return uri;
}
@Override
public String path() {
if (path == null) {
path = UriParser.path(uri());
}
return path;
}
@Override
public String query() {
if (query == null) {
query = UriParser.query(uri());
}
return query;
}
@Override
public HttpServerResponse response() {
return response;
}
@Override
public MultiMap headers() {
if (headers == null) {
headers = new HttpHeadersAdapter(request.headers());
}
return headers;
}
@Override
public MultiMap params() {
if (params == null) {
QueryStringDecoder queryStringDecoder = new QueryStringDecoder(uri());
Map> prms = queryStringDecoder.parameters();
params = new CaseInsensitiveMultiMap();
if (!prms.isEmpty()) {
for (Map.Entry> entry : prms.entrySet()) {
params.add(entry.getKey(), entry.getValue());
}
}
}
return params;
}
@Override
public HttpServerRequest dataHandler(Handler dataHandler) {
this.dataHandler = dataHandler;
return this;
}
@Override
public HttpServerRequest exceptionHandler(Handler handler) {
this.exceptionHandler = handler;
return this;
}
@Override
public HttpServerRequest pause() {
conn.pause();
return this;
}
@Override
public HttpServerRequest resume() {
conn.resume();
return this;
}
@Override
public HttpServerRequest endHandler(Handler handler) {
this.endHandler = handler;
return this;
}
@Override
public InetSocketAddress remoteAddress() {
return conn.remoteAddress();
}
@Override
public URI absoluteURI() {
if (absoluteURI == null) {
try {
URI uri = new URI(uri());
String scheme = uri.getScheme();
if (scheme != null && (scheme.equals("http") || scheme.equals("https"))) {
absoluteURI = uri;
} else {
absoluteURI = new URI(conn.getServerOrigin() + uri);
}
} catch (URISyntaxException e) {
log.error("Failed to create abs uri", e);
}
}
return absoluteURI;
}
@Override
public X509Certificate[] peerCertificateChain() throws SSLPeerUnverifiedException {
return conn.getPeerCertificateChain();
}
@Override
public HttpServerRequest bodyHandler(final Handler bodyHandler) {
final Buffer body = new Buffer();
dataHandler(new Handler() {
public void handle(Buffer buff) {
body.appendBuffer(buff);
}
});
endHandler(new VoidHandler() {
public void handle() {
bodyHandler.handle(body);
}
});
return this;
}
@Override
public NetSocket netSocket() {
if (netSocket == null) {
netSocket = conn.createNetSocket();
}
return netSocket;
}
@Override
public HttpServerRequest uploadHandler(Handler handler) {
this.uploadHandler = handler;
return this;
}
@Override
public MultiMap formAttributes() {
if (decoder == null) {
throw new IllegalStateException("Call expectMultiPart(true) before request body is received to receive form attributes");
}
return attributes();
}
@Override
public HttpServerRequest expectMultiPart(boolean expect) {
if (expect) {
String contentType = request.headers().get(HttpHeaders.Names.CONTENT_TYPE);
if (contentType != null) {
HttpMethod method = request.getMethod();
String lowerCaseContentType = contentType.toLowerCase();
boolean isURLEncoded = lowerCaseContentType.startsWith(HttpHeaders.Values.APPLICATION_X_WWW_FORM_URLENCODED);
if ((lowerCaseContentType.startsWith(HttpHeaders.Values.MULTIPART_FORM_DATA) || isURLEncoded) &&
(method.equals(HttpMethod.POST) || method.equals(HttpMethod.PUT) || method.equals(HttpMethod.PATCH))) {
decoder = new HttpPostRequestDecoder(new DataFactory(), request);
}
}
} else {
decoder = null;
}
return this;
}
void handleData(Buffer data) {
if (decoder != null) {
try {
decoder.offer(new DefaultHttpContent(data.getByteBuf().duplicate()));
} catch (HttpPostRequestDecoder.ErrorDataDecoderException e) {
handleException(e);
}
}
if (dataHandler != null) {
dataHandler.handle(data);
}
}
void handleEnd() {
if (decoder != null) {
try {
decoder.offer(LastHttpContent.EMPTY_LAST_CONTENT);
while (decoder.hasNext()) {
InterfaceHttpData data = decoder.next();
if (data instanceof Attribute) {
Attribute attr = (Attribute) data;
try {
attributes().add(attr.getName(), attr.getValue());
} catch (Exception e) {
// Will never happen, anyway handle it somehow just in case
handleException(e);
}
}
}
} catch (HttpPostRequestDecoder.ErrorDataDecoderException e) {
handleException(e);
} catch (HttpPostRequestDecoder.EndOfDataDecoderException e) {
// ignore this as it is expected
} finally {
decoder.destroy();
}
}
if (endHandler != null) {
endHandler.handle(null);
}
}
void handleException(Throwable t) {
if (exceptionHandler != null) {
exceptionHandler.handle(t);
}
}
private MultiMap attributes() {
// Create it lazily
if (attributes == null) {
attributes = new CaseInsensitiveMultiMap();
}
return attributes;
}
@Override
public InetSocketAddress localAddress() {
return conn.localAddress();
}
private final static class NettyFileUpload implements FileUpload {
private final DefaultHttpServerFileUpload upload;
private String name;
private String filename;
private String contentType;
private String contentTransferEncoding;
private Charset charset;
private boolean completed;
private NettyFileUpload(DefaultHttpServerFileUpload upload, String name, String filename, String contentType, String contentTransferEncoding, Charset charset) {
this.upload = upload;
this.name = name;
this.filename = filename;
this.contentType = contentType;
this.contentTransferEncoding = contentTransferEncoding;
this.charset = charset;
}
@Override
public void setContent(ByteBuf channelBuffer) throws IOException {
completed = true;
upload.receiveData(new Buffer(channelBuffer));
upload.complete();
}
@Override
public void addContent(ByteBuf channelBuffer, boolean last) throws IOException {
upload.receiveData(new Buffer(channelBuffer));
if (last) {
completed = true;
upload.complete();
}
}
@Override
public void setContent(File file) throws IOException {
throw new UnsupportedOperationException();
}
@Override
public void setContent(InputStream inputStream) throws IOException {
throw new UnsupportedOperationException();
}
@Override
public boolean isCompleted() {
return completed;
}
@Override
public long length() {
throw new UnsupportedOperationException();
}
@Override
public void delete() {
throw new UnsupportedOperationException();
}
@Override
public byte[] get() throws IOException {
throw new UnsupportedOperationException();
}
@Override
public ByteBuf getChunk(int i) throws IOException {
throw new UnsupportedOperationException();
}
@Override
public String getString() throws IOException {
throw new UnsupportedOperationException();
}
@Override
public String getString(Charset charset) throws IOException {
throw new UnsupportedOperationException();
}
@Override
public Charset getCharset() {
return charset;
}
@Override
public void setCharset(Charset charset) {
this.charset = charset;
}
@Override
public boolean renameTo(File file) throws IOException {
throw new UnsupportedOperationException();
}
@Override
public boolean isInMemory() {
return false;
}
@Override
public File getFile() throws IOException {
throw new UnsupportedOperationException();
}
@Override
public String getName() {
return name;
}
@Override
public HttpDataType getHttpDataType() {
throw new UnsupportedOperationException();
}
@Override
public int compareTo(InterfaceHttpData o) {
return 0;
}
@Override
public String getFilename() {
return filename;
}
@Override
public void setFilename(String filename) {
this.filename = filename;
}
@Override
public String getContentType() {
return contentType;
}
@Override
public void setContentType(String contentType) {
this.contentType = contentType;
}
@Override
public String getContentTransferEncoding() {
return contentTransferEncoding;
}
@Override
public void setContentTransferEncoding(String contentTransferEncoding) {
this.contentTransferEncoding = contentTransferEncoding;
}
@Override
public ByteBuf getByteBuf() throws IOException {
throw new UnsupportedOperationException();
}
@Override
public FileUpload copy() {
throw new UnsupportedOperationException();
}
//@Override
public FileUpload duplicate() {
throw new UnsupportedOperationException();
}
@Override
public FileUpload retain() {
return this;
}
@Override
public FileUpload retain(int increment) {
return this;
}
@Override
public ByteBuf content() {
throw new UnsupportedOperationException();
}
@Override
public int refCnt() {
return 1;
}
@Override
public boolean release() {
return false;
}
@Override
public boolean release(int decrement) {
return false;
}
}
private class DataFactory extends DefaultHttpDataFactory {
DataFactory() {
super(false);
}
@Override
public FileUpload createFileUpload(HttpRequest httpRequest, String name, String filename, String contentType, String contentTransferEncoding, Charset charset, long size) {
DefaultHttpServerFileUpload upload = new DefaultHttpServerFileUpload(conn.async(), DefaultHttpServerRequest.this, name, filename, contentType, contentTransferEncoding, charset,
size);
NettyFileUpload nettyUpload = new NettyFileUpload(upload, name, filename, contentType,
contentTransferEncoding, charset);
if (uploadHandler != null) {
uploadHandler.handle(upload);
}
return nettyUpload;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy