1/* 2 * Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 8 * - Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 11 * - Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * - Neither the name of Oracle nor the names of its 16 * contributors may be used to endorse or promote products derived 17 * from this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 20 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 21 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 24 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 25 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 26 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 27 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 28 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32/* 33 * This source code is provided to illustrate the usage of a given feature 34 * or technique and has been deliberately simplified. Additional steps 35 * required for a production-quality application, such as security checks, 36 * input validation and proper error handling, might not be present in 37 * this sample code. 38 */ 39 40 41import java.io.*; 42import java.nio.*; 43import java.nio.channels.*; 44 45/** 46 * Primary driver class used by non-blocking Servers to receive, 47 * prepare, send, and shutdown requests. 48 * 49 * @author Mark Reinhold 50 * @author Brad R. Wetmore 51 */ 52class RequestHandler implements Handler { 53 54 private ChannelIO cio; 55 private ByteBuffer rbb = null; 56 57 private boolean requestReceived = false; 58 private Request request = null; 59 private Reply reply = null; 60 61 private static int created = 0; 62 63 RequestHandler(ChannelIO cio) { 64 this.cio = cio; 65 66 // Simple heartbeat to let user know we're alive. 67 synchronized (RequestHandler.class) { 68 created++; 69 if ((created % 50) == 0) { 70 System.out.println("."); 71 created = 0; 72 } else { 73 System.out.print("."); 74 } 75 } 76 } 77 78 // Returns true when request is complete 79 // May expand rbb if more room required 80 // 81 private boolean receive(SelectionKey sk) throws IOException { 82 ByteBuffer tmp = null; 83 84 if (requestReceived) { 85 return true; 86 } 87 88 if (!cio.doHandshake(sk)) { 89 return false; 90 } 91 92 if ((cio.read() < 0) || Request.isComplete(cio.getReadBuf())) { 93 rbb = cio.getReadBuf(); 94 return (requestReceived = true); 95 } 96 return false; 97 } 98 99 // When parse is successfull, saves request and returns true 100 // 101 private boolean parse() throws IOException { 102 try { 103 request = Request.parse(rbb); 104 return true; 105 } catch (MalformedRequestException x) { 106 reply = new Reply(Reply.Code.BAD_REQUEST, 107 new StringContent(x)); 108 } 109 return false; 110 } 111 112 // Ensures that reply field is non-null 113 // 114 private void build() throws IOException { 115 Request.Action action = request.action(); 116 if ((action != Request.Action.GET) && 117 (action != Request.Action.HEAD)) { 118 reply = new Reply(Reply.Code.METHOD_NOT_ALLOWED, 119 new StringContent(request.toString())); 120 } 121 reply = new Reply(Reply.Code.OK, 122 new FileContent(request.uri()), action); 123 } 124 125 public void handle(SelectionKey sk) throws IOException { 126 try { 127 128 if (request == null) { 129 if (!receive(sk)) 130 return; 131 rbb.flip(); 132 if (parse()) 133 build(); 134 try { 135 reply.prepare(); 136 } catch (IOException x) { 137 reply.release(); 138 reply = new Reply(Reply.Code.NOT_FOUND, 139 new StringContent(x)); 140 reply.prepare(); 141 } 142 if (send()) { 143 // More bytes remain to be written 144 sk.interestOps(SelectionKey.OP_WRITE); 145 } else { 146 // Reply completely written; we're done 147 if (cio.shutdown()) { 148 cio.close(); 149 reply.release(); 150 } 151 } 152 } else { 153 if (!send()) { // Should be rp.send() 154 if (cio.shutdown()) { 155 cio.close(); 156 reply.release(); 157 } 158 } 159 } 160 } catch (IOException x) { 161 String m = x.getMessage(); 162 if (!m.equals("Broken pipe") && 163 !m.equals("Connection reset by peer")) { 164 System.err.println("RequestHandler: " + x.toString()); 165 } 166 167 try { 168 /* 169 * We had a failure here, so we'll try to be nice 170 * before closing down and send off a close_notify, 171 * but if we can't get the message off with one try, 172 * we'll just shutdown. 173 */ 174 cio.shutdown(); 175 } catch (IOException e) { 176 // ignore 177 } 178 179 cio.close(); 180 if (reply != null) { 181 reply.release(); 182 } 183 } 184 185 } 186 187 private boolean send() throws IOException { 188 try { 189 return reply.send(cio); 190 } catch (IOException x) { 191 if (x.getMessage().startsWith("Resource temporarily")) { 192 System.err.println("## RTA"); 193 return true; 194 } 195 throw x; 196 } 197 } 198} 199