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