Created
May 10, 2017 01:00
-
-
Save rahulsh1/6681465d802ffd7d841ec67c1b1347cb to your computer and use it in GitHub Desktop.
Netty Http File Upload
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package my.netty.http.upload; | |
import io.netty.channel.Channel; | |
import io.netty.channel.ChannelInitializer; | |
import io.netty.channel.ChannelPipeline; | |
import io.netty.channel.EventLoopGroup; | |
import io.netty.channel.nio.NioEventLoopGroup; | |
import io.netty.channel.socket.SocketChannel; | |
import io.netty.channel.socket.nio.NioServerSocketChannel; | |
import io.netty.handler.codec.http.HttpRequestDecoder; | |
import io.netty.handler.codec.http.HttpResponseEncoder; | |
/** | |
* Class for initializing HTTP Handlers. | |
*/ | |
final class HttpUploadServerInitializer extends ChannelInitializer<SocketChannel> { | |
@Override | |
protected void initChannel(final SocketChannel socketChannel) throws Exception { | |
final ChannelPipeline pipeline = socketChannel.pipeline(); | |
pipeline.addLast(new HttpRequestDecoder()); | |
pipeline.addLast(new HttpResponseEncoder()); | |
pipeline.addLast(new MyHttUploadServerHandler()); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package my.netty.http.upload; | |
import io.netty.buffer.ByteBuf; | |
import io.netty.buffer.Unpooled; | |
import io.netty.channel.ChannelFutureListener; | |
import io.netty.channel.ChannelHandlerContext; | |
import io.netty.channel.SimpleChannelInboundHandler; | |
import io.netty.handler.codec.http.DefaultFullHttpResponse; | |
import io.netty.handler.codec.http.FullHttpResponse; | |
import io.netty.handler.codec.http.HttpContent; | |
import io.netty.handler.codec.http.HttpHeaderNames; | |
import io.netty.handler.codec.http.HttpObject; | |
import io.netty.handler.codec.http.HttpRequest; | |
import io.netty.handler.codec.http.HttpResponseStatus; | |
import io.netty.handler.codec.http.LastHttpContent; | |
import io.netty.handler.codec.http.multipart.DefaultHttpDataFactory; | |
import io.netty.handler.codec.http.multipart.FileUpload; | |
import io.netty.handler.codec.http.multipart.HttpDataFactory; | |
import io.netty.handler.codec.http.multipart.HttpPostRequestDecoder; | |
import io.netty.handler.codec.http.multipart.InterfaceHttpData; | |
import io.netty.util.CharsetUtil; | |
import java.io.File; | |
import java.io.FileInputStream; | |
import java.io.FileOutputStream; | |
import java.io.IOException; | |
import java.net.URI; | |
import java.nio.channels.FileChannel; | |
import static io.netty.handler.codec.http.HttpMethod.POST; | |
import static io.netty.handler.codec.http.HttpResponseStatus.CREATED; | |
import static io.netty.handler.codec.http.HttpResponseStatus.METHOD_NOT_ALLOWED; | |
import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1; | |
/** | |
* Handles uploading of file and then saves it to a known location. | |
*/ | |
public class MyHttUploadServerHandler extends SimpleChannelInboundHandler<HttpObject> { | |
// Factory that writes to disk | |
private static final HttpDataFactory factory = new DefaultHttpDataFactory(true); | |
private static final String FILE_UPLOAD_LOCN = "/tmp/uploads/"; | |
private HttpRequest httpRequest; | |
private HttpPostRequestDecoder httpDecoder; | |
@Override | |
protected void channelRead0(final ChannelHandlerContext ctx, final HttpObject httpObject) | |
throws Exception { | |
if (httpObject instanceof HttpRequest) { | |
httpRequest = (HttpRequest) httpObject; | |
final URI uri = new URI(httpRequest.uri()); | |
System.out.println("Got URI " + uri); | |
if (httpRequest.method() == POST) { | |
httpDecoder = new HttpPostRequestDecoder(factory, httpRequest); | |
httpDecoder.setDiscardThreshold(0); | |
} else { | |
sendResponse(ctx, METHOD_NOT_ALLOWED, null); | |
} | |
} | |
if (httpDecoder != null) { | |
if (httpObject instanceof HttpContent) { | |
final HttpContent chunk = (HttpContent) httpObject; | |
httpDecoder.offer(chunk); | |
readChunk(ctx); | |
if (chunk instanceof LastHttpContent) { | |
resetPostRequestDecoder(); | |
} | |
} | |
} | |
} | |
private void readChunk(ChannelHandlerContext ctx) throws IOException { | |
while (httpDecoder.hasNext()) { | |
InterfaceHttpData data = httpDecoder.next(); | |
if (data != null) { | |
try { | |
switch (data.getHttpDataType()) { | |
case Attribute: | |
break; | |
case FileUpload: | |
final FileUpload fileUpload = (FileUpload) data; | |
final File file = new File(FILE_UPLOAD_LOCN + fileUpload.getFilename()); | |
if (!file.exists()) { | |
file.createNewFile(); | |
} | |
System.out.println("Created file " + file); | |
try (FileChannel inputChannel = new FileInputStream(fileUpload.getFile()).getChannel(); | |
FileChannel outputChannel = new FileOutputStream(file).getChannel()) { | |
outputChannel.transferFrom(inputChannel, 0, inputChannel.size()); | |
sendResponse(ctx, CREATED, "file name: " + file.getAbsolutePath()); | |
} | |
break; | |
} | |
} finally { | |
data.release(); | |
} | |
} | |
} | |
} | |
/** | |
* Sends a response back. | |
* @param ctx | |
* @param status | |
* @param message | |
*/ | |
private static void sendResponse(ChannelHandlerContext ctx, HttpResponseStatus status, String message) { | |
final FullHttpResponse response; | |
String msgDesc = message; | |
if (message == null) { | |
msgDesc = "Failure: " + status; | |
} | |
msgDesc += " \r\n"; | |
final ByteBuf buffer = Unpooled.copiedBuffer(msgDesc, CharsetUtil.UTF_8); | |
if (status.code() >= HttpResponseStatus.BAD_REQUEST.code()) { | |
response = new DefaultFullHttpResponse(HTTP_1_1, status, buffer); | |
} else { | |
response = new DefaultFullHttpResponse(HTTP_1_1, status, buffer); | |
} | |
response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/plain; charset=UTF-8"); | |
// Close the connection as soon as the response is sent. | |
ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE); | |
} | |
private void resetPostRequestDecoder() { | |
httpRequest = null; | |
httpDecoder.destroy(); | |
httpDecoder = null; | |
} | |
@Override | |
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { | |
System.out.println("Got exception " + cause); | |
ctx.channel().close(); | |
} | |
@Override | |
public void channelInactive(ChannelHandlerContext ctx) throws Exception { | |
if (httpDecoder != null) { | |
httpDecoder.cleanFiles(); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Tanks, its useful.