1
2
3
4
5
6
7
8
9
10
11
12
13
14 package org.eclipse.jetty.http;
15
16 import java.io.IOException;
17
18 import org.eclipse.jetty.io.Buffer;
19 import org.eclipse.jetty.io.Buffers;
20 import org.eclipse.jetty.io.ByteArrayBuffer;
21 import org.eclipse.jetty.io.EndPoint;
22 import org.eclipse.jetty.io.EofException;
23 import org.eclipse.jetty.io.View;
24 import org.eclipse.jetty.util.log.Log;
25
26
27
28
29
30
31
32
33
34
35
36
37 public abstract class AbstractGenerator implements Generator
38 {
39
40 public final static int STATE_HEADER = 0;
41 public final static int STATE_CONTENT = 2;
42 public final static int STATE_FLUSHING = 3;
43 public final static int STATE_END = 4;
44
45 public static final byte[] NO_BYTES = {};
46 public static final int MAX_OUTPUT_CHARS = 512;
47
48
49
50 protected final Buffers _buffers;
51 protected final EndPoint _endp;
52 protected final int _headerBufferSize;
53 protected int _contentBufferSize;
54
55 protected int _state = STATE_HEADER;
56
57 protected int _status = 0;
58 protected int _version = HttpVersions.HTTP_1_1_ORDINAL;
59 protected Buffer _reason;
60 protected Buffer _method;
61 protected String _uri;
62
63 protected long _contentWritten = 0;
64 protected long _contentLength = HttpTokens.UNKNOWN_CONTENT;
65 protected boolean _last = false;
66 protected boolean _head = false;
67 protected boolean _noContent = false;
68 protected boolean _close = false;
69
70
71 protected Buffer _header;
72 protected Buffer _buffer;
73 protected Buffer _content;
74
75 private boolean _sendServerVersion;
76
77
78
79
80
81
82
83
84
85
86 public AbstractGenerator(Buffers buffers, EndPoint io, int headerBufferSize, int contentBufferSize)
87 {
88 this._buffers = buffers;
89 this._endp = io;
90 _headerBufferSize=headerBufferSize;
91 _contentBufferSize=contentBufferSize;
92 }
93
94
95 public boolean isOpen()
96 {
97 return _endp.isOpen();
98 }
99
100
101 public void reset(boolean returnBuffers)
102 {
103 _state = STATE_HEADER;
104 _status = 0;
105 _version = HttpVersions.HTTP_1_1_ORDINAL;
106 _reason = null;
107 _last = false;
108 _head = false;
109 _noContent=false;
110 _close = false;
111 _contentWritten = 0;
112 _contentLength = HttpTokens.UNKNOWN_CONTENT;
113
114 synchronized(this)
115 {
116 if (returnBuffers)
117 {
118 if (_header != null)
119 _buffers.returnBuffer(_header);
120 _header = null;
121 if (_buffer != null)
122 _buffers.returnBuffer(_buffer);
123 _buffer = null;
124 }
125 else
126 {
127 if (_header != null)
128 _header.clear();
129
130 if (_buffer != null)
131 {
132 _buffers.returnBuffer(_buffer);
133 _buffer = null;
134 }
135 }
136 }
137 _content = null;
138 _method=null;
139 }
140
141
142 public void resetBuffer()
143 {
144 if(_state>=STATE_FLUSHING)
145 throw new IllegalStateException("Flushed");
146
147 _last = false;
148 _close = false;
149 _contentWritten = 0;
150 _contentLength = HttpTokens.UNKNOWN_CONTENT;
151 _content=null;
152 if (_buffer!=null)
153 _buffer.clear();
154 }
155
156
157
158
159
160 public int getContentBufferSize()
161 {
162 return _contentBufferSize;
163 }
164
165
166
167
168
169 public void increaseContentBufferSize(int contentBufferSize)
170 {
171 if (contentBufferSize > _contentBufferSize)
172 {
173 _contentBufferSize = contentBufferSize;
174 if (_buffer != null)
175 {
176 Buffer nb = _buffers.getBuffer(_contentBufferSize);
177 nb.put(_buffer);
178 _buffers.returnBuffer(_buffer);
179 _buffer = nb;
180 }
181 }
182 }
183
184
185 public Buffer getUncheckedBuffer()
186 {
187 return _buffer;
188 }
189
190
191 public boolean getSendServerVersion ()
192 {
193 return _sendServerVersion;
194 }
195
196
197 public void setSendServerVersion (boolean sendServerVersion)
198 {
199 _sendServerVersion = sendServerVersion;
200 }
201
202
203 public int getState()
204 {
205 return _state;
206 }
207
208
209 public boolean isState(int state)
210 {
211 return _state == state;
212 }
213
214
215 public boolean isComplete()
216 {
217 return _state == STATE_END;
218 }
219
220
221 public boolean isIdle()
222 {
223 return _state == STATE_HEADER && _method==null && _status==0;
224 }
225
226
227 public boolean isCommitted()
228 {
229 return _state != STATE_HEADER;
230 }
231
232
233
234
235
236 public boolean isHead()
237 {
238 return _head;
239 }
240
241
242 public void setContentLength(long value)
243 {
244 if (value<0)
245 _contentLength=HttpTokens.UNKNOWN_CONTENT;
246 else
247 _contentLength=value;
248 }
249
250
251
252
253
254 public void setHead(boolean head)
255 {
256 _head = head;
257 }
258
259
260
261
262
263
264 public boolean isPersistent()
265 {
266 return !_close;
267 }
268
269
270 public void setPersistent(boolean persistent)
271 {
272 _close=!persistent;
273 }
274
275
276
277
278
279
280 public void setVersion(int version)
281 {
282 if (_state != STATE_HEADER)
283 throw new IllegalStateException("STATE!=START "+_state);
284 _version = version;
285 if (_version==HttpVersions.HTTP_0_9_ORDINAL && _method!=null)
286 _noContent=true;
287 }
288
289
290 public int getVersion()
291 {
292 return _version;
293 }
294
295
296
297
298 public void setRequest(String method, String uri)
299 {
300 if (method==null || HttpMethods.GET.equals(method) )
301 _method=HttpMethods.GET_BUFFER;
302 else
303 _method=HttpMethods.CACHE.lookup(method);
304 _uri=uri;
305 if (_version==HttpVersions.HTTP_0_9_ORDINAL)
306 _noContent=true;
307 }
308
309
310
311
312
313
314 public void setResponse(int status, String reason)
315 {
316 if (_state != STATE_HEADER) throw new IllegalStateException("STATE!=START");
317 _method=null;
318 _status = status;
319 if (reason!=null)
320 {
321 int len=reason.length();
322 if (len>_headerBufferSize/2)
323 len=_headerBufferSize/2;
324 _reason=new ByteArrayBuffer(len);
325 for (int i=0;i<len;i++)
326 {
327 char ch = reason.charAt(i);
328 if (ch!='\r'&&ch!='\n')
329 _reason.put((byte)ch);
330 else
331 _reason.put((byte)' ');
332 }
333 }
334 }
335
336
337
338
339
340
341
342 public abstract int prepareUncheckedAddContent() throws IOException;
343
344
345 void uncheckedAddContent(int b)
346 {
347 _buffer.put((byte)b);
348 }
349
350
351 public void completeUncheckedAddContent()
352 {
353 if (_noContent)
354 {
355 if(_buffer!=null)
356 _buffer.clear();
357 return;
358 }
359 else
360 {
361 _contentWritten+=_buffer.length();
362 if (_head)
363 _buffer.clear();
364 }
365 }
366
367
368 public boolean isBufferFull()
369 {
370 if (_buffer != null && _buffer.space()==0)
371 {
372 if (_buffer.length()==0 && !_buffer.isImmutable())
373 _buffer.compact();
374 return _buffer.space()==0;
375 }
376
377 return _content!=null && _content.length()>0;
378 }
379
380
381 public boolean isContentWritten()
382 {
383 return _contentLength>=0 && _contentWritten>=_contentLength;
384 }
385
386
387 public abstract void completeHeader(HttpFields fields, boolean allContentAdded) throws IOException;
388
389
390
391
392
393
394
395 public void complete() throws IOException
396 {
397 if (_state == STATE_HEADER)
398 {
399 throw new IllegalStateException("State==HEADER");
400 }
401
402 if (_contentLength >= 0 && _contentLength != _contentWritten && !_head)
403 {
404 if (Log.isDebugEnabled())
405 Log.debug("ContentLength written=="+_contentWritten+" != contentLength=="+_contentLength);
406 _close = true;
407 }
408 }
409
410
411 public abstract long flushBuffer() throws IOException;
412
413
414
415 public void flush(long maxIdleTime) throws IOException
416 {
417
418 Buffer content = _content;
419 Buffer buffer = _buffer;
420 if (content!=null && content.length()>0 || buffer!=null && buffer.length()>0 || isBufferFull())
421 {
422 flushBuffer();
423
424 while ((content!=null && content.length()>0 ||buffer!=null && buffer.length()>0) && _endp.isOpen())
425 blockForOutput(maxIdleTime);
426 }
427 }
428
429
430
431
432
433
434
435
436
437
438
439
440 public void sendError(int code, String reason, String content, boolean close) throws IOException
441 {
442 if (!isCommitted())
443 {
444 setResponse(code, reason);
445 _close = close;
446 completeHeader(null, false);
447 if (content != null)
448 addContent(new View(new ByteArrayBuffer(content)), Generator.LAST);
449 complete();
450 }
451 }
452
453
454
455
456
457 public long getContentWritten()
458 {
459 return _contentWritten;
460 }
461
462
463
464
465 public void blockForOutput(long maxIdleTime) throws IOException
466 {
467 if (_endp.isBlocking())
468 {
469 try
470 {
471 flushBuffer();
472 }
473 catch(IOException e)
474 {
475 _endp.close();
476 throw e;
477 }
478 }
479 else
480 {
481 if (!_endp.blockWritable(maxIdleTime))
482 {
483 _endp.close();
484 throw new EofException("timeout");
485 }
486
487 flushBuffer();
488 }
489 }
490
491 }