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