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