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