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