| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you 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 org.apache.tajo.storage.http; |
| |
| import io.netty.buffer.Unpooled; |
| import io.netty.channel.*; |
| import io.netty.handler.codec.http.*; |
| import io.netty.handler.codec.http.HttpHeaders.Names; |
| import io.netty.util.CharsetUtil; |
| import org.apache.commons.logging.Log; |
| import org.apache.commons.logging.LogFactory; |
| |
| import javax.activation.MimetypesFileTypeMap; |
| import java.io.File; |
| import java.io.FileNotFoundException; |
| import java.io.IOException; |
| import java.io.RandomAccessFile; |
| import java.net.URI; |
| import java.net.URISyntaxException; |
| import java.net.URL; |
| |
| import static io.netty.handler.codec.http.HttpHeaders.Names.CONTENT_TYPE; |
| import static io.netty.handler.codec.http.HttpResponseStatus.BAD_REQUEST; |
| import static io.netty.handler.codec.http.HttpResponseStatus.OK; |
| import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1; |
| |
| public class ExampleHttpServerHandler extends SimpleChannelInboundHandler<FullHttpRequest> { |
| |
| private static final Log LOG = LogFactory.getLog(ExampleHttpServerHandler.class); |
| |
| @Override |
| protected void channelRead0(ChannelHandlerContext context, FullHttpRequest request) throws Exception { |
| |
| if (request.getMethod().equals(HttpMethod.HEAD)) { |
| |
| processHead(context, request); |
| |
| } else if (request.getMethod().equals(HttpMethod.GET)) { |
| |
| processGet(context, request); |
| |
| } else { |
| // error |
| String msg = "Not supported method: " + request.getMethod(); |
| LOG.error(msg); |
| context.writeAndFlush(getBadRequest(msg)); |
| } |
| } |
| |
| private void processHead(ChannelHandlerContext context, FullHttpRequest request) { |
| HttpHeaders headers = request.headers(); |
| FullHttpResponse response = null; |
| |
| if (headers.contains(Names.CONTENT_LENGTH)) { |
| |
| try { |
| File file = getRequestedFile(request.getUri()); |
| |
| response = new DefaultFullHttpResponse( |
| HTTP_1_1, |
| request.getDecoderResult().isSuccess() ? OK : BAD_REQUEST |
| ); |
| |
| HttpHeaders.setContentLength(response, file.length()); |
| |
| |
| } catch (FileNotFoundException | URISyntaxException e) { |
| response = getBadRequest(e.getMessage()); |
| } |
| } |
| |
| context.writeAndFlush(response); |
| } |
| |
| private void processGet(ChannelHandlerContext context, FullHttpRequest request) { |
| try { |
| File file = getRequestedFile(request.getUri()); |
| |
| RandomAccessFile raf = new RandomAccessFile(file, "r"); |
| long fileLength = raf.length(); |
| |
| HttpResponse response = new DefaultHttpResponse(HTTP_1_1, OK); |
| HttpHeaders.setContentLength(response, fileLength); |
| setContentTypeHeader(response, file); |
| |
| context.write(response); |
| |
| context.write(new DefaultFileRegion(raf.getChannel(), 0, fileLength)); |
| |
| // Write the end marker. |
| ChannelFuture future = context.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT); |
| future.addListener(ChannelFutureListener.CLOSE); |
| |
| } catch (IOException | URISyntaxException e) { |
| context.writeAndFlush(getBadRequest(e.getMessage())); |
| } |
| } |
| |
| private static File getRequestedFile(String uri) throws FileNotFoundException, URISyntaxException { |
| String path = URI.create(uri).getPath(); |
| URL url = ClassLoader.getSystemResource("dataset/" + path); |
| |
| if (url == null) { |
| throw new FileNotFoundException(uri); |
| } |
| return new File(url.toURI()); |
| } |
| |
| private static FullHttpResponse getBadRequest(String message) { |
| return new DefaultFullHttpResponse(HTTP_1_1, BAD_REQUEST, |
| Unpooled.copiedBuffer(message, CharsetUtil.UTF_8)); |
| } |
| |
| @Override |
| public void exceptionCaught(ChannelHandlerContext context, Throwable cause) { |
| LOG.error(cause.getMessage(), cause); |
| if (context.channel().isOpen()) { |
| context.channel().close(); |
| } |
| } |
| |
| /** |
| * Sets the content type header for the HTTP Response |
| * @param response HTTP response |
| * @param file file to extract content type |
| */ |
| private static void setContentTypeHeader(HttpResponse response, File file) { |
| MimetypesFileTypeMap mimeTypesMap = new MimetypesFileTypeMap(); |
| response.headers().set(CONTENT_TYPE, mimeTypesMap.getContentType(file.getPath())); |
| } |
| } |