View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2013 Mort Bay Consulting Pty. Ltd.
4   //  ------------------------------------------------------------------------
5   //  All rights reserved. This program and the accompanying materials
6   //  are made available under the terms of the Eclipse Public License v1.0
7   //  and Apache License v2.0 which accompanies this distribution.
8   //
9   //      The Eclipse Public License is available at
10  //      http://www.eclipse.org/legal/epl-v10.html
11  //
12  //      The Apache License v2.0 is available at
13  //      http://www.opensource.org/licenses/apache2.0.php
14  //
15  //  You may elect to redistribute this code under either of these licenses.
16  //  ========================================================================
17  //
18  
19  package org.eclipse.jetty.server;
20  
21  import java.io.IOException;
22  import java.nio.ByteBuffer;
23  
24  import org.eclipse.jetty.util.BlockingCallback;
25  import org.eclipse.jetty.util.BufferUtil;
26  import org.eclipse.jetty.util.Callback;
27  import org.eclipse.jetty.util.log.Log;
28  import org.eclipse.jetty.util.log.Logger;
29  
30  public class HttpInputOverHTTP extends HttpInput<ByteBuffer> implements Callback
31  {
32      private static final Logger LOG = Log.getLogger(HttpInputOverHTTP.class);
33      private final BlockingCallback _readBlocker = new BlockingCallback();
34      private final HttpConnection _httpConnection;
35      private ByteBuffer _content;
36  
37      /**
38       * @param httpConnection
39       */
40      public HttpInputOverHTTP(HttpConnection httpConnection)
41      {
42          _httpConnection = httpConnection;
43      }
44  
45      @Override
46      public void recycle()
47      {
48          synchronized (lock())
49          {
50              super.recycle();
51              _content=null;
52          }
53      }
54  
55      @Override
56      protected void blockForContent() throws IOException
57      {
58          while(true)
59          {
60              _httpConnection.fillInterested(_readBlocker);
61              LOG.debug("{} block readable on {}",this,_readBlocker);
62              _readBlocker.block();
63  
64              Object content=getNextContent();
65              if (content!=null || isFinished())
66                  break;
67          }
68      }
69  
70      @Override
71      public String toString()
72      {
73          return String.format("%s@%x",getClass().getSimpleName(),hashCode());
74      }
75  
76      @Override
77      protected ByteBuffer nextContent() throws IOException
78      {
79          // If we have some content available, return it
80          if (BufferUtil.hasContent(_content))
81              return _content;
82  
83          // No - then we are going to need to parse some more content
84          _content=null;
85          ByteBuffer requestBuffer = _httpConnection.getRequestBuffer();
86  
87          while (!_httpConnection.getParser().isComplete())
88          {
89              // Can the parser progress (even with an empty buffer)
90              _httpConnection.getParser().parseNext(requestBuffer==null?BufferUtil.EMPTY_BUFFER:requestBuffer);
91  
92              // If we got some content, that will do for now!
93              if (BufferUtil.hasContent(_content))
94                  return _content;
95  
96              // No, we can we try reading some content?
97              if (BufferUtil.isEmpty(requestBuffer) && _httpConnection.getEndPoint().isInputShutdown())
98              {
99                  _httpConnection.getParser().atEOF();
100                 continue;
101             }
102 
103             // OK lets read some data
104             int filled=_httpConnection.getEndPoint().fill(requestBuffer);
105             if (LOG.isDebugEnabled()) // Avoid boxing of variable 'filled'
106                 LOG.debug("{} filled {}",this,filled);
107             if (filled<=0)
108             {
109                 if (filled<0)
110                 {
111                     _httpConnection.getParser().atEOF();
112                     continue;
113                 }
114                 return null;
115             }
116         }
117 
118         return null;
119 
120     }
121 
122     @Override
123     protected int remaining(ByteBuffer item)
124     {
125         return item.remaining();
126     }
127 
128     @Override
129     protected int get(ByteBuffer item, byte[] buffer, int offset, int length)
130     {
131         int l = Math.min(item.remaining(), length);
132         item.get(buffer, offset, l);
133         return l;
134     }
135 
136     @Override
137     protected void consume(ByteBuffer item, int length)
138     {
139         item.position(item.position()+length);
140     }
141 
142     @Override
143     public void content(ByteBuffer item)
144     {
145         if (BufferUtil.hasContent(_content))
146             throw new IllegalStateException();
147         _content=item;
148     }
149 
150     @Override
151     protected void unready()
152     {
153         _httpConnection.fillInterested(this);
154     }
155 
156     @Override
157     public void succeeded()
158     {
159         _httpConnection.getHttpChannel().getState().onReadPossible();
160     }
161 
162     @Override
163     public void failed(Throwable x)
164     {
165         super.failed(x);
166         _httpConnection.getHttpChannel().getState().onReadPossible();
167     }
168 }