KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > freecs > core > ConnectionBuffer


1 /**
2  * Copyright (C) 2003 Manfred Andres
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17  */

18 package freecs.core;
19
20 import freecs.*;
21 import freecs.content.*;
22 import freecs.interfaces.*;
23 import freecs.util.ObjectBuffer;
24 import java.nio.ByteBuffer JavaDoc;
25 import java.nio.channels.SelectionKey JavaDoc;
26 import java.nio.channels.SocketChannel JavaDoc;
27 import freecs.util.TrafficMonitor;
28 import java.net.InetAddress JavaDoc;
29
30 /**
31  * gets attached to the keys reading from a nonblocking channel
32  * stores the raw request in a buffer. if the request is finished, parse gets
33  * called which in turn decides which requestobject to use for this requst
34  * and suplies this RequestObject to the next available RequestEvaluator
35  */

36 public class ConnectionBuffer {
37    private volatile User u;
38    private int src;
39    private ByteBuffer JavaDoc buf;
40    private ByteBuffer JavaDoc tBuf = null;
41    public ByteBuffer JavaDoc rBuf = ByteBuffer.allocate (Server.srv.READBUFFER_SIZE);
42    private SelectionKey JavaDoc sk;
43    private String JavaDoc ts;
44    private ObjectBuffer writeBuffer = new ObjectBuffer (Server.srv.INITIAL_RESPONSE_QUEUE);
45    private volatile boolean valid=true;
46    public Connection conn;
47
48    private StringBuffer JavaDoc lsb = new StringBuffer JavaDoc();
49    
50    private static final int GET = 1;
51    private static final int POST= 2;
52
53    private int reqType = 0;
54    private int so = 0;
55    private int cStart = -1;
56    private int cLength = -1;
57    public volatile IRequest currentRequest;
58    private boolean reading=false;
59    
60     private volatile long closeWhen=System.currentTimeMillis() + Server.srv.KEEP_ALIVE_TIMEOUT;
61
62
63    public ConnectionBuffer (int src) {
64       this.src = src;
65       buf = ByteBuffer.allocate(Server.srv.READBUFFER_SIZE);
66       if (Server.TRACE_CREATE_AND_FINALIZE)
67           Server.log (this, "++++++++++++++++++++++++++++++++++++++++CREATE", Server.MSG_STATE, Server.LVL_VERY_VERBOSE);
68    }
69
70     /**
71      * appends to the incomplete request and checks if it has completed
72      * if the request is complete, it will be returned. NULL will be returned
73      * on the other hand.
74      * FIXME: has to get more modular to support different protocols
75      * @return IRequst The full request || null if incomplete
76      */

77     public IRequest append () throws Exception JavaDoc {
78         boolean parse = false;
79         synchronized (this) {
80             reading=true;
81             rBuf.flip();
82             if (this.buf.remaining () < rBuf.remaining ()) {
83                 ByteBuffer JavaDoc tbuf = ByteBuffer.allocate (this.buf.position () + rBuf.remaining ());
84                 this.buf.flip ();
85                 tbuf.put(this.buf);
86                 this.buf = tbuf;
87             }
88             this.buf.put(rBuf);
89             rBuf.clear ();
90             if (reqType == 0 && this.buf.position () > 4) {
91                 if (this.buf.get(0) == 'P' && this.buf.get(1) == 'O' && this.buf.get(2) == 'S' && this.buf.get(3) == 'T') {
92                     reqType = POST;
93                 } else if (this.buf.get(0) == 'G' && this.buf.get(1) == 'E' && this.buf.get(2) == 'T') {
94                     reqType = GET;
95                 } else {
96                     this.addLog("HEADER-INVALID");
97                     this.invalidate();
98                     reading=false;
99                     return null;
100                 }
101             }
102             if (reqType == GET) {
103                 if (this.buf.position() > 4096) {
104                     this.addLog("HEADER>4096bytes");
105                     this.invalidate();
106                     reading=false;
107                     return null;
108                 }
109                 if (this.buf.position () > 10
110                     && this.buf.get (this.buf.position () - 4) == '\r'
111                     && this.buf.get (this.buf.position () - 3) == '\n'
112                     && this.buf.get (this.buf.position () - 2) == '\r'
113                     && this.buf.get (this.buf.position () - 1) == '\n') {
114                         parse = true;
115                 }
116             } else if (reqType == POST) {
117                 if (cLength == -1) {
118                     for (; so < this.buf.position () - 15; so++) {
119                         if (so > 4096
120                             || (this.buf.get(so) == '\r'
121                                 && this.buf.get(so+1) == '\n'
122                                 && this.buf.get(so+2) == '\r'
123                                 && this.buf.get(so+3) == '\n')) {
124                             this.addLog("HEADER-INVALID");
125                             this.invalidate();
126                             reading=false;
127                             return null;
128                         }
129                         if (this.buf.get(so) == 'C' && this.buf.get(so+1) == 'o'
130                                 && this.buf.get(so+2) == 'n' && this.buf.get(so+3) == 't'
131                                 && this.buf.get(so+4) == 'e' && this.buf.get(so+5) == 'n'
132                                 && this.buf.get(so+6) == 't' && this.buf.get(so+7) == '-'
133                                 && (this.buf.get(so+8) == 'L' || this.buf.get(so+8) == 'l')
134                                 && this.buf.get(so+9) == 'e' && this.buf.get(so+10) == 'n'
135                                 && this.buf.get(so+11) == 'g' && this.buf.get(so+12) == 't'
136                                 && this.buf.get(so+13) == 'h' && this.buf.get(so+14) == ':') {
137                             int cso = so + 14;
138                             if (cso >= this.buf.capacity ()) return null;
139                             while ((this.buf.get(cso) < 48 || this.buf.get(cso) > 57)) {
140                                 if (cso >= this.buf.capacity ()) return null;
141                                 cso++;
142                             }
143                             StringBuffer JavaDoc sb = new StringBuffer JavaDoc ();
144                             while (this.buf.get(cso) >= 48 && this.buf.get(cso) <= 57) {
145                                 if (cso >= this.buf.capacity ()) return null;
146                                 sb.append ((char) this.buf.get(cso));
147                                 cso++;
148                             }
149                             so = cso;
150                             cLength = Integer.parseInt (sb.toString ());
151                             break;
152                         }
153                     }
154                 }
155                 if (cLength != -1) {
156                     for (; cStart == -1 && so < this.buf.position () - 4; so++) {
157                         if (so > 4096) {
158                             this.addLog("HEADER>4096bytes");
159                             this.invalidate();
160                             reading=false;
161                             return null;
162                         }
163                         if (this.buf.get(so) == '\r'
164                                 && this.buf.get(so+1) == '\n'
165                                 && this.buf.get(so+2) == '\r'
166                                 && this.buf.get(so+3) == '\n') {
167                             cStart = so + 4;
168                             break;
169                         }
170                     }
171                     if (cStart != -1) {
172                         if ((this.buf.position () - cStart) > cLength) {
173                             int diff = this.buf.position () - cStart - cLength;
174                             tBuf = ByteBuffer.allocate (diff);
175                             for (int pos = this.buf.position () - diff; pos < this.buf.position (); pos++) {
176                                 tBuf.put (this.buf.get (pos));
177                             }
178                             this.buf.position(cStart + cLength);
179                             parse=true;
180                         } else if ((this.buf.position () - cStart) == cLength) {
181                             parse=true;
182                         }
183                     }
184                 }
185             }
186         }
187         if (parse)
188             return parse();
189         return null;
190     }
191
192     /**
193      * hands over this buffer to the requestparser-threads which take care of parsing the request
194      * @return IRequest The IRequest-object containing the request
195      */

196     public IRequest parse () throws Exception JavaDoc {
197         // FIXME: when we install another protocol we have to check here for the type of protocol
198
IRequest req = null;
199         synchronized (this) {
200             this.buf.flip ();
201             try {
202                 req = new HTTPRequest(buf, this);
203             } catch (Exception JavaDoc e) {
204                 reset();
205                 throw e;
206             }
207             reading=false;
208         }
209         try {
210             req.parse ();
211             Connection conn = req.getConnectionObject();
212             if (!conn.isDirectlyConnected) {
213                 InetAddress JavaDoc ia = ((SocketChannel JavaDoc) sk.channel ()).socket().getInetAddress ();
214                 if (ia != null) {
215                     TrafficMonitor.tm.markAsProxy (ia);
216                 }
217             }
218 /* } catch (Exception e) {
219             Server.debug (this, "parse: ", e, Server.MSG_ERROR, Server.LVL_MAJOR);
220             throw e; */

221         } finally {
222             reset ();
223         }
224         return req;
225     }
226
227     private synchronized void reset () {
228       if (buf.capacity () != Server.srv.READBUFFER_SIZE) {
229          buf = ByteBuffer.allocate (Server.srv.READBUFFER_SIZE);
230       } else {
231          buf.clear ();
232       }
233       if (tBuf != null) {
234          buf.put (tBuf);
235          tBuf = null;
236       }
237       cStart = -1;
238       cLength= -1;
239       reqType= 0;
240       so = 0;
241       valid=true;
242       reading=false;
243    }
244
245    public void setTemplateSet (String JavaDoc ts) {
246       this.ts = ts;
247    }
248
249    public String JavaDoc getTemplateSet () {
250       return ts;
251    }
252
253    public void setUser (User u) {
254       this.u = u;
255    }
256
257    public User getUser () {
258       return u;
259    }
260
261     /**
262     * returns the SocketChannel of this requestbuffer
263     */

264    public SelectionKey JavaDoc getKey () {
265       return sk;
266    }
267     
268     public void setKey (SelectionKey JavaDoc sk) {
269         if (!CentralSelector.isSkValid(sk)) {
270             Server.log(this, "setKey: tryed to set invalid key", Server.MSG_STATE, Server.LVL_VERBOSE);
271             return;
272         }
273         this.sk=sk;
274         conn = new Connection (sk);
275     }
276
277     public void addToWrite (Object JavaDoc ic) {
278         if (!CentralSelector.isSkValid(sk)) {
279             Server.log (this, "addToWrite: selection-key isn't valid anymore", Server.MSG_STATE, Server.LVL_VERBOSE);
280             return;
281         }
282         synchronized (this) {
283             if (writeBuffer.isFull ()) {
284                 int newSize = writeBuffer.capacity () + Server.srv.INITIAL_RESPONSE_QUEUE;
285                 if (newSize > Server.srv.MAX_RESPONSE_QUEUE) {
286                     Server.log(this, "addToWrite: write-queue would be bigger than specified for " + toString(), Server.MSG_STATE, Server.LVL_MINOR);
287                     return;
288                 }
289                 Server.log(this, "addToWrite: Expanding write-queue for " + toString(), Server.MSG_STATE, Server.LVL_MINOR);
290                 writeBuffer.resizeTo(newSize);
291             }
292             writeBuffer.put(ic);
293         }
294         writeToLog();
295         Responder.res.addToWrite((SocketChannel JavaDoc) sk.channel(), this);
296     }
297
298     public ObjectBuffer getWriteQueue () {
299         return writeBuffer;
300     }
301
302     public void updateKeepAliveTimeout () {
303         if (isMessageFrame)
304             return;
305         closeWhen = System.currentTimeMillis() + Server.srv.KEEP_ALIVE_TIMEOUT;
306     }
307     
308     public long getKeepAliveTimeout(long ts) {
309         if (isMessageFrame || reading)
310             return -1;
311         return closeWhen;
312     }
313     
314     public void invalidate() {
315         valid=false;
316     }
317     
318     public boolean isValid() {
319         return valid;
320     }
321     
322     private volatile boolean isMessageFrame = false;
323     public void setIsMessageFrame(boolean b) {
324         // Server.log("changed state to message-frame-state", Server.MSG_STATE, Server.LVL_MAJOR);
325
isMessageFrame=b;
326     }
327     
328     public void addLog (String JavaDoc str) {
329         lsb.append (" ");
330         lsb.append (str);
331     }
332
333     public void writeToLog () {
334         if (lsb.length() < 1)
335             return;
336         if (conn!=null && conn.peerAddress != null)
337             lsb.insert(0, conn.peerAddress.getHostAddress());
338         else if (conn != null)
339             lsb.insert(0, conn.toString());
340         else
341             lsb.insert(0, "undefined");
342         Server.log ("OK", lsb.toString (), Server.MSG_TRAFFIC, Server.LVL_MINOR);
343         lsb = new StringBuffer JavaDoc();
344     }
345
346     public void logError (String JavaDoc reason) {
347         lsb.append (" REASON: ");
348         lsb.append (reason);
349         if (conn != null && conn.peerAddress != null)
350             lsb.insert (0, conn.peerAddress.getHostAddress());
351         else if (conn != null)
352             lsb.insert (0, conn.toString());
353         else
354             lsb.insert (0, "undefined");
355         Server.log ("FAILED", lsb.toString (), Server.MSG_TRAFFIC, Server.LVL_MAJOR);
356         lsb = new StringBuffer JavaDoc();
357     }
358
359     public void finalize() {
360         if (Server.TRACE_CREATE_AND_FINALIZE)
361             Server.log(this, "----------------------------------------FINALIZED", Server.MSG_STATE, Server.LVL_VERY_VERBOSE);
362     }
363 }
Popular Tags