View Javadoc

1   // ========================================================================
2   // Copyright (c) 2010-2011 Mort Bay Consulting Pty. Ltd.
3   // ------------------------------------------------------------------------
4   // All rights reserved. This program and the accompanying materials
5   // are made available under the terms of the Eclipse Public License v1.0
6   // and Apache License v2.0 which accompanies this distribution.
7   // The Eclipse Public License is available at 
8   // http://www.eclipse.org/legal/epl-v10.html
9   // The Apache License v2.0 is available at
10  // http://www.opensource.org/licenses/apache2.0.php
11  // You may elect to redistribute this code under either of these licenses. 
12  // ========================================================================
13  package org.eclipse.jetty.nested;
14  
15  import java.io.IOException;
16  
17  import javax.servlet.http.HttpServletResponse;
18  
19  import org.eclipse.jetty.http.AbstractGenerator;
20  import org.eclipse.jetty.http.HttpFields;
21  import org.eclipse.jetty.http.HttpHeaders;
22  import org.eclipse.jetty.http.HttpVersions;
23  import org.eclipse.jetty.io.Buffer;
24  import org.eclipse.jetty.io.Buffers;
25  import org.eclipse.jetty.io.EndPoint;
26  import org.eclipse.jetty.server.Server;
27  import org.eclipse.jetty.util.log.Log;
28  import org.eclipse.jetty.util.log.Logger;
29  
30  public class NestedGenerator extends AbstractGenerator
31  {
32      private static final Logger LOG = Log.getLogger(NestedGenerator.class);
33  
34      final HttpServletResponse _response;
35      final String _nestedIn;
36      
37      public NestedGenerator(Buffers buffers, EndPoint io, HttpServletResponse response, String nestedIn)
38      {
39          super(buffers,io);
40          _response=response;
41          _nestedIn=nestedIn;
42      }
43  
44      public void addContent(Buffer content, boolean last) throws IOException
45      {
46          LOG.debug("addContent {} {}",content.length(),last);
47          if (_noContent)
48          {
49              content.clear();
50              return;
51          }
52  
53          if (content.isImmutable())
54              throw new IllegalArgumentException("immutable");
55  
56          if (_last || _state == STATE_END)
57          {
58              LOG.debug("Ignoring extra content {}", content);
59              content.clear();
60              return;
61          }
62          _last = last;
63  
64          if(!_endp.isOpen())
65          {
66              _state = STATE_END;
67              return;
68          }
69  
70          // Handle any unfinished business?
71          if (_content != null && _content.length() > 0)
72          {
73              flushBuffer();
74              if (_content != null && _content.length() > 0)
75                  throw new IllegalStateException("FULL");
76          }
77  
78          _content = content;
79  
80          _contentWritten += content.length();
81  
82          // Handle the _content
83          if (_head)
84          {
85              content.clear();
86              _content = null;
87          }
88          else if (!last || _buffer!=null)
89          {
90              // Yes - so we better check we have a buffer
91              initBuffer();
92              // Copy _content to buffer;
93              int len = 0;
94              len = _buffer.put(_content);
95  
96              // make sure there is space for a trailing null   (???)
97              if (len > 0 && _buffer.space() == 0)
98              {
99                  len--;
100                 _buffer.setPutIndex(_buffer.putIndex() - 1);
101             }
102             
103             LOG.debug("copied {} to buffer",len);
104 
105             _content.skip(len);
106 
107             if (_content.length() == 0)
108                 _content = null;
109         }
110     }
111 
112     public boolean addContent(byte b) throws IOException
113     {
114         // LOG.debug("addContent 1");
115         if (_noContent)
116             return false;
117 
118         if (_last || _state == STATE_END)
119             throw new IllegalStateException("Closed");
120 
121 
122         if(!_endp.isOpen())
123         {
124             _state = STATE_END;
125             return false;
126         }
127 
128         // Handle any unfinished business?
129         if (_content != null && _content.length() > 0)
130         {
131             flushBuffer();
132             if (_content != null && _content.length() > 0)
133                 throw new IllegalStateException("FULL");
134         }
135 
136         _contentWritten++;
137 
138         // Handle the _content
139         if (_head)
140             return false;
141 
142         // we better check we have a buffer
143         initBuffer();
144 
145         // Copy _content to buffer;
146 
147         _buffer.put(b);
148 
149         return _buffer.space() <= 1;
150     }
151 
152     /* ------------------------------------------------------------ */
153     private void initBuffer() throws IOException
154     {
155         if (_buffer == null)
156         {
157             // LOG.debug("initContent");
158             _buffer = _buffers.getBuffer();
159         }
160     }
161 
162     /* ------------------------------------------------------------ */
163     @Override
164     public boolean isRequest()
165     {
166         return false;
167     }
168 
169     /* ------------------------------------------------------------ */
170     @Override
171     public boolean isResponse()
172     {
173         return true;
174     }
175 
176     /* ------------------------------------------------------------ */
177     @Override
178     public int prepareUncheckedAddContent() throws IOException
179     {
180         initBuffer();
181         return _buffer.space();
182     }
183 
184     /* ------------------------------------------------------------ */
185     @Override
186     public void completeHeader(HttpFields fields, boolean allContentAdded) throws IOException
187     {
188         if (LOG.isDebugEnabled())
189             LOG.debug("completeHeader: {}",fields.toString().trim().replace("\r\n","|"));
190         if (_state != STATE_HEADER)
191             return;
192 
193         if (_last && !allContentAdded)
194             throw new IllegalStateException("last?");
195         _last = _last | allContentAdded;
196 
197         if (_persistent==null)
198             _persistent=(_version > HttpVersions.HTTP_1_0_ORDINAL);
199 
200 
201         if (_reason == null)
202             _response.setStatus(_status);
203         else
204             _response.setStatus(_status,_reason.toString());
205 
206         if (_status == 100 || _status == 204 || _status == 304)
207         {
208             _noContent = true;
209             _content = null;
210         }
211 
212 
213         boolean has_server = false;
214         if (fields != null)
215         {
216             // Add headers
217             int s=fields.size();
218             for (int f=0;f<s;f++)
219             {
220                 HttpFields.Field field = fields.getField(f);
221                 if (field==null)
222                     continue;
223                 _response.setHeader(field.getName(),field.getValue());
224             }
225         }
226 
227         if (!has_server && _status > 100 && getSendServerVersion())
228             _response.setHeader(HttpHeaders.SERVER,"Jetty("+Server.getVersion()+",nested in "+_nestedIn+")");
229 
230         _state = STATE_CONTENT;
231     }
232 
233     /* ------------------------------------------------------------ */
234     /**
235      * Complete the message.
236      *
237      * @throws IOException
238      */
239     @Override
240     public void complete() throws IOException
241     {
242         if (_state == STATE_END)
243             return;
244 
245         super.complete();
246 
247         if (_state < STATE_FLUSHING)
248             _state = STATE_FLUSHING;
249 
250         flushBuffer();
251     }
252 
253     /* ------------------------------------------------------------ */
254     @Override
255     public long flushBuffer() throws IOException
256     {
257         if (_state == STATE_HEADER)
258             throw new IllegalStateException("State==HEADER");
259         
260         int len = 0;
261         
262         if (_buffer==null)
263         {
264             
265             if (_content!=null && _content.length()>0)
266             {
267                 // flush content directly
268                 len = _endp.flush(_content);
269                 if (len>0)
270                     _content.skip(len);
271             }
272         }
273         else
274         {
275             if (_buffer.length()==0 && _content!=null && _content.length()>0)
276             {
277                 // Copy content to buffer
278                 _content.skip(_buffer.put(_content));
279             }
280 
281             int size=_buffer.length();
282             len =_endp.flush(_buffer);
283             LOG.debug("flushBuffer {} of {}",len,size);
284             if (len>0)
285                 _buffer.skip(len);
286         }
287         
288         if (_content!=null && _content.length()==0)
289             _content=null;
290         if (_buffer!=null && _buffer.length()==0 && _content==null)
291         {
292             _buffers.returnBuffer(_buffer);
293             _buffer=null;
294         }
295         
296         if (_state==STATE_FLUSHING && _buffer==null && _content==null)
297             _state=STATE_END;
298 
299         return len;
300     }
301 
302 }