Crossfire JXClient, Trunk
RequestHandler.java
Go to the documentation of this file.
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 
41 import java.io.*;
42 import java.nio.*;
43 import java.nio.channels.*;
44 
52 class 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 }