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  
74              flushBuffer();
75              if (_content != null && _content.length() > 0)
76                  throw new IllegalStateException("FULL");
77          }
78  
79          _content = content;
80  
81          _contentWritten += content.length();
82  
83          // Handle the _content
84          if (_head)
85          {
86              content.clear();
87              _content = null;
88          }
89          else
90          {
91              // Yes - so we better check we have a buffer
92              initContent();
93              // Copy _content to buffer;
94              int len = 0;
95              len = _buffer.put(_content);
96  
97              // make sure there is space for a trailing null
98              if (len > 0 && _buffer.space() == 0)
99              {
100                 len--;
101                 _buffer.setPutIndex(_buffer.putIndex() - 1);
102             }
103 
104             _content.skip(len);
105 
106             if (_content.length() == 0)
107                 _content = null;
108         }
109     }
110 
111     public boolean addContent(byte b) throws IOException
112     {
113         // LOG.debug("addContent 1");
114         if (_noContent)
115             return false;
116 
117         if (_last || _state == STATE_END)
118             throw new IllegalStateException("Closed");
119 
120 
121         if(!_endp.isOpen())
122         {
123             _state = STATE_END;
124             return false;
125         }
126 
127         // Handle any unfinished business?
128         if (_content != null && _content.length() > 0)
129         {
130             flushBuffer();
131             if (_content != null && _content.length() > 0)
132                 throw new IllegalStateException("FULL");
133         }
134 
135         _contentWritten++;
136 
137         // Handle the _content
138         if (_head)
139             return false;
140 
141         // we better check we have a buffer
142         initContent();
143 
144         // Copy _content to buffer;
145 
146         _buffer.put(b);
147 
148         return _buffer.space() <= 1;
149     }
150 
151     /* ------------------------------------------------------------ */
152     private void initContent() throws IOException
153     {
154         if (_buffer == null)
155         {
156             // LOG.debug("initContent");
157             _buffer = _buffers.getBuffer();
158         }
159     }
160 
161     /* ------------------------------------------------------------ */
162     @Override
163     public boolean isRequest()
164     {
165         return false;
166     }
167 
168     /* ------------------------------------------------------------ */
169     @Override
170     public boolean isResponse()
171     {
172         return true;
173     }
174 
175     /* ------------------------------------------------------------ */
176     @Override
177     public int prepareUncheckedAddContent() throws IOException
178     {
179         initContent();
180         return _buffer.space();
181     }
182 
183     /* ------------------------------------------------------------ */
184     @Override
185     public void completeHeader(HttpFields fields, boolean allContentAdded) throws IOException
186     {
187         if (LOG.isDebugEnabled())
188             LOG.debug("completeHeader: {}",fields.toString().trim().replace("\r\n","|"));
189         if (_state != STATE_HEADER)
190             return;
191 
192         if (_last && !allContentAdded)
193             throw new IllegalStateException("last?");
194         _last = _last | allContentAdded;
195 
196         if (_persistent==null)
197             _persistent=(_version > HttpVersions.HTTP_1_0_ORDINAL);
198 
199 
200         if (_reason == null)
201             _response.setStatus(_status);
202         else
203             _response.setStatus(_status,_reason.toString());
204 
205         if (_status == 100 || _status == 204 || _status == 304)
206         {
207             _noContent = true;
208             _content = null;
209         }
210 
211 
212         boolean has_server = false;
213         if (fields != null)
214         {
215             // Add headers
216             int s=fields.size();
217             for (int f=0;f<s;f++)
218             {
219                 HttpFields.Field field = fields.getField(f);
220                 if (field==null)
221                     continue;
222                 _response.setHeader(field.getName(),field.getValue());
223             }
224         }
225 
226         if (!has_server && _status > 100 && getSendServerVersion())
227             _response.setHeader(HttpHeaders.SERVER,"Jetty("+Server.getVersion()+",nested in "+_nestedIn+")");
228 
229         _state = STATE_CONTENT;
230     }
231 
232     /* ------------------------------------------------------------ */
233     @Override
234     public long flushBuffer() throws IOException
235     {
236         if (_state == STATE_HEADER)
237             throw new IllegalStateException("State==HEADER");
238         
239 
240         if (_content != null && _content.length() < _buffer.space() && _state != STATE_FLUSHING)
241         {
242             initContent();
243             _buffer.put(_content);
244             _content.clear();
245             _content = null;
246         }
247         
248         if (_buffer==null)
249             return 0;
250         
251         int size=_buffer.length();
252         int len = _buffer==null?0:_endp.flush(_buffer);
253         LOG.debug("flushBuffer {} of {}",len,size);
254         if (len>0)
255             _buffer.skip(len);
256 
257         return len;
258     }
259 
260 }