Mercurial Hosting > luan
comparison src/org/eclipse/jetty/http/AbstractGenerator.java @ 802:3428c60d7cfc
replace jetty jars with source
author | Franklin Schmidt <fschmidt@gmail.com> |
---|---|
date | Wed, 07 Sep 2016 21:15:48 -0600 |
parents | |
children | 8e9db0bbf4f9 |
comparison
equal
deleted
inserted
replaced
801:6a21393191c1 | 802:3428c60d7cfc |
---|---|
1 // | |
2 // ======================================================================== | |
3 // Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. | |
4 // ------------------------------------------------------------------------ | |
5 // All rights reserved. This program and the accompanying materials | |
6 // are made available under the terms of the Eclipse Public License v1.0 | |
7 // and Apache License v2.0 which accompanies this distribution. | |
8 // | |
9 // The Eclipse Public License is available at | |
10 // http://www.eclipse.org/legal/epl-v10.html | |
11 // | |
12 // The Apache License v2.0 is available at | |
13 // http://www.opensource.org/licenses/apache2.0.php | |
14 // | |
15 // You may elect to redistribute this code under either of these licenses. | |
16 // ======================================================================== | |
17 // | |
18 | |
19 package org.eclipse.jetty.http; | |
20 | |
21 import java.io.IOException; | |
22 | |
23 import org.eclipse.jetty.io.Buffer; | |
24 import org.eclipse.jetty.io.Buffers; | |
25 import org.eclipse.jetty.io.ByteArrayBuffer; | |
26 import org.eclipse.jetty.io.EndPoint; | |
27 import org.eclipse.jetty.io.EofException; | |
28 import org.eclipse.jetty.io.View; | |
29 import org.eclipse.jetty.util.log.Log; | |
30 import org.eclipse.jetty.util.log.Logger; | |
31 | |
32 /* ------------------------------------------------------------ */ | |
33 /** | |
34 * Abstract Generator. Builds HTTP Messages. | |
35 * | |
36 * Currently this class uses a system parameter "jetty.direct.writers" to control | |
37 * two optional writer to byte conversions. buffer.writers=true will probably be | |
38 * faster, but will consume more memory. This option is just for testing and tuning. | |
39 * | |
40 */ | |
41 public abstract class AbstractGenerator implements Generator | |
42 { | |
43 private static final Logger LOG = Log.getLogger(AbstractGenerator.class); | |
44 | |
45 // states | |
46 public final static int STATE_HEADER = 0; | |
47 public final static int STATE_CONTENT = 2; | |
48 public final static int STATE_FLUSHING = 3; | |
49 public final static int STATE_END = 4; | |
50 | |
51 public static final byte[] NO_BYTES = {}; | |
52 | |
53 // data | |
54 | |
55 protected final Buffers _buffers; // source of buffers | |
56 protected final EndPoint _endp; | |
57 | |
58 protected int _state = STATE_HEADER; | |
59 | |
60 protected int _status = 0; | |
61 protected int _version = HttpVersions.HTTP_1_1_ORDINAL; | |
62 protected Buffer _reason; | |
63 protected Buffer _method; | |
64 protected String _uri; | |
65 | |
66 protected long _contentWritten = 0; | |
67 protected long _contentLength = HttpTokens.UNKNOWN_CONTENT; | |
68 protected boolean _last = false; | |
69 protected boolean _head = false; | |
70 protected boolean _noContent = false; | |
71 protected Boolean _persistent = null; | |
72 | |
73 protected Buffer _header; // Buffer for HTTP header (and maybe small _content) | |
74 protected Buffer _buffer; // Buffer for copy of passed _content | |
75 protected Buffer _content; // Buffer passed to addContent | |
76 | |
77 protected Buffer _date; | |
78 | |
79 private boolean _sendServerVersion; | |
80 | |
81 | |
82 /* ------------------------------------------------------------------------------- */ | |
83 /** | |
84 * Constructor. | |
85 * | |
86 * @param buffers buffer pool | |
87 * @param io the end point | |
88 */ | |
89 public AbstractGenerator(Buffers buffers, EndPoint io) | |
90 { | |
91 this._buffers = buffers; | |
92 this._endp = io; | |
93 } | |
94 | |
95 /* ------------------------------------------------------------------------------- */ | |
96 public abstract boolean isRequest(); | |
97 | |
98 /* ------------------------------------------------------------------------------- */ | |
99 public abstract boolean isResponse(); | |
100 | |
101 /* ------------------------------------------------------------------------------- */ | |
102 public boolean isOpen() | |
103 { | |
104 return _endp.isOpen(); | |
105 } | |
106 | |
107 /* ------------------------------------------------------------------------------- */ | |
108 public void reset() | |
109 { | |
110 _state = STATE_HEADER; | |
111 _status = 0; | |
112 _version = HttpVersions.HTTP_1_1_ORDINAL; | |
113 _reason = null; | |
114 _last = false; | |
115 _head = false; | |
116 _noContent=false; | |
117 _persistent = null; | |
118 _contentWritten = 0; | |
119 _contentLength = HttpTokens.UNKNOWN_CONTENT; | |
120 _date = null; | |
121 | |
122 _content = null; | |
123 _method=null; | |
124 } | |
125 | |
126 /* ------------------------------------------------------------------------------- */ | |
127 public void returnBuffers() | |
128 { | |
129 if (_buffer!=null && _buffer.length()==0) | |
130 { | |
131 _buffers.returnBuffer(_buffer); | |
132 _buffer=null; | |
133 } | |
134 | |
135 if (_header!=null && _header.length()==0) | |
136 { | |
137 _buffers.returnBuffer(_header); | |
138 _header=null; | |
139 } | |
140 } | |
141 | |
142 /* ------------------------------------------------------------------------------- */ | |
143 public void resetBuffer() | |
144 { | |
145 if(_state>=STATE_FLUSHING) | |
146 throw new IllegalStateException("Flushed"); | |
147 | |
148 _last = false; | |
149 _persistent=null; | |
150 _contentWritten = 0; | |
151 _contentLength = HttpTokens.UNKNOWN_CONTENT; | |
152 _content=null; | |
153 if (_buffer!=null) | |
154 _buffer.clear(); | |
155 } | |
156 | |
157 /* ------------------------------------------------------------ */ | |
158 /** | |
159 * @return Returns the contentBufferSize. | |
160 */ | |
161 public int getContentBufferSize() | |
162 { | |
163 if (_buffer==null) | |
164 _buffer=_buffers.getBuffer(); | |
165 return _buffer.capacity(); | |
166 } | |
167 | |
168 /* ------------------------------------------------------------ */ | |
169 /** | |
170 * @param contentBufferSize The contentBufferSize to set. | |
171 */ | |
172 public void increaseContentBufferSize(int contentBufferSize) | |
173 { | |
174 if (_buffer==null) | |
175 _buffer=_buffers.getBuffer(); | |
176 if (contentBufferSize > _buffer.capacity()) | |
177 { | |
178 Buffer nb = _buffers.getBuffer(contentBufferSize); | |
179 nb.put(_buffer); | |
180 _buffers.returnBuffer(_buffer); | |
181 _buffer = nb; | |
182 } | |
183 } | |
184 | |
185 /* ------------------------------------------------------------ */ | |
186 public Buffer getUncheckedBuffer() | |
187 { | |
188 return _buffer; | |
189 } | |
190 | |
191 /* ------------------------------------------------------------ */ | |
192 public boolean getSendServerVersion () | |
193 { | |
194 return _sendServerVersion; | |
195 } | |
196 | |
197 /* ------------------------------------------------------------ */ | |
198 public void setSendServerVersion (boolean sendServerVersion) | |
199 { | |
200 _sendServerVersion = sendServerVersion; | |
201 } | |
202 | |
203 /* ------------------------------------------------------------ */ | |
204 public int getState() | |
205 { | |
206 return _state; | |
207 } | |
208 | |
209 /* ------------------------------------------------------------ */ | |
210 public boolean isState(int state) | |
211 { | |
212 return _state == state; | |
213 } | |
214 | |
215 /* ------------------------------------------------------------ */ | |
216 public boolean isComplete() | |
217 { | |
218 return _state == STATE_END; | |
219 } | |
220 | |
221 /* ------------------------------------------------------------ */ | |
222 public boolean isIdle() | |
223 { | |
224 return _state == STATE_HEADER && _method==null && _status==0; | |
225 } | |
226 | |
227 /* ------------------------------------------------------------ */ | |
228 public boolean isCommitted() | |
229 { | |
230 return _state != STATE_HEADER; | |
231 } | |
232 | |
233 /* ------------------------------------------------------------ */ | |
234 /** | |
235 * @return Returns the head. | |
236 */ | |
237 public boolean isHead() | |
238 { | |
239 return _head; | |
240 } | |
241 | |
242 /* ------------------------------------------------------------ */ | |
243 public void setContentLength(long value) | |
244 { | |
245 if (value<0) | |
246 _contentLength=HttpTokens.UNKNOWN_CONTENT; | |
247 else | |
248 _contentLength=value; | |
249 } | |
250 | |
251 /* ------------------------------------------------------------ */ | |
252 /** | |
253 * @param head The head to set. | |
254 */ | |
255 public void setHead(boolean head) | |
256 { | |
257 _head = head; | |
258 } | |
259 | |
260 /* ------------------------------------------------------------ */ | |
261 /** | |
262 * @return <code>false</code> if the connection should be closed after a request has been read, | |
263 * <code>true</code> if it should be used for additional requests. | |
264 */ | |
265 public boolean isPersistent() | |
266 { | |
267 return _persistent!=null | |
268 ?_persistent.booleanValue() | |
269 :(isRequest()?true:_version>HttpVersions.HTTP_1_0_ORDINAL); | |
270 } | |
271 | |
272 /* ------------------------------------------------------------ */ | |
273 public void setPersistent(boolean persistent) | |
274 { | |
275 _persistent=persistent; | |
276 } | |
277 | |
278 /* ------------------------------------------------------------ */ | |
279 /** | |
280 * @param version The version of the client the response is being sent to (NB. Not the version | |
281 * in the response, which is the version of the server). | |
282 */ | |
283 public void setVersion(int version) | |
284 { | |
285 if (_state != STATE_HEADER) | |
286 throw new IllegalStateException("STATE!=START "+_state); | |
287 _version = version; | |
288 if (_version==HttpVersions.HTTP_0_9_ORDINAL && _method!=null) | |
289 _noContent=true; | |
290 } | |
291 | |
292 /* ------------------------------------------------------------ */ | |
293 public int getVersion() | |
294 { | |
295 return _version; | |
296 } | |
297 | |
298 /* ------------------------------------------------------------ */ | |
299 /** | |
300 * @see org.eclipse.jetty.http.Generator#setDate(org.eclipse.jetty.io.Buffer) | |
301 */ | |
302 public void setDate(Buffer timeStampBuffer) | |
303 { | |
304 _date=timeStampBuffer; | |
305 } | |
306 | |
307 /* ------------------------------------------------------------ */ | |
308 /** | |
309 */ | |
310 public void setRequest(String method, String uri) | |
311 { | |
312 if (method==null || HttpMethods.GET.equals(method) ) | |
313 _method=HttpMethods.GET_BUFFER; | |
314 else | |
315 _method=HttpMethods.CACHE.lookup(method); | |
316 _uri=uri; | |
317 if (_version==HttpVersions.HTTP_0_9_ORDINAL) | |
318 _noContent=true; | |
319 } | |
320 | |
321 /* ------------------------------------------------------------ */ | |
322 /** | |
323 * @param status The status code to send. | |
324 * @param reason the status message to send. | |
325 */ | |
326 public void setResponse(int status, String reason) | |
327 { | |
328 if (_state != STATE_HEADER) throw new IllegalStateException("STATE!=START"); | |
329 _method=null; | |
330 _status = status; | |
331 if (reason!=null) | |
332 { | |
333 int len=reason.length(); | |
334 | |
335 // TODO don't hard code | |
336 if (len>1024) | |
337 len=1024; | |
338 _reason=new ByteArrayBuffer(len); | |
339 for (int i=0;i<len;i++) | |
340 { | |
341 char ch = reason.charAt(i); | |
342 if (ch!='\r'&&ch!='\n') | |
343 _reason.put((byte)ch); | |
344 else | |
345 _reason.put((byte)' '); | |
346 } | |
347 } | |
348 } | |
349 | |
350 /* ------------------------------------------------------------ */ | |
351 /** Prepare buffer for unchecked writes. | |
352 * Prepare the generator buffer to receive unchecked writes | |
353 * @return the available space in the buffer. | |
354 * @throws IOException | |
355 */ | |
356 public abstract int prepareUncheckedAddContent() throws IOException; | |
357 | |
358 /* ------------------------------------------------------------ */ | |
359 void uncheckedAddContent(int b) | |
360 { | |
361 _buffer.put((byte)b); | |
362 } | |
363 | |
364 /* ------------------------------------------------------------ */ | |
365 public void completeUncheckedAddContent() | |
366 { | |
367 if (_noContent) | |
368 { | |
369 if(_buffer!=null) | |
370 _buffer.clear(); | |
371 } | |
372 else | |
373 { | |
374 _contentWritten+=_buffer.length(); | |
375 if (_head) | |
376 _buffer.clear(); | |
377 } | |
378 } | |
379 | |
380 /* ------------------------------------------------------------ */ | |
381 public boolean isBufferFull() | |
382 { | |
383 if (_buffer != null && _buffer.space()==0) | |
384 { | |
385 if (_buffer.length()==0 && !_buffer.isImmutable()) | |
386 _buffer.compact(); | |
387 return _buffer.space()==0; | |
388 } | |
389 | |
390 return _content!=null && _content.length()>0; | |
391 } | |
392 | |
393 /* ------------------------------------------------------------ */ | |
394 public boolean isWritten() | |
395 { | |
396 return _contentWritten>0; | |
397 } | |
398 | |
399 /* ------------------------------------------------------------ */ | |
400 public boolean isAllContentWritten() | |
401 { | |
402 return _contentLength>=0 && _contentWritten>=_contentLength; | |
403 } | |
404 | |
405 /* ------------------------------------------------------------ */ | |
406 public abstract void completeHeader(HttpFields fields, boolean allContentAdded) throws IOException; | |
407 | |
408 /* ------------------------------------------------------------ */ | |
409 /** | |
410 * Complete the message. | |
411 * | |
412 * @throws IOException | |
413 */ | |
414 public void complete() throws IOException | |
415 { | |
416 if (_state == STATE_HEADER) | |
417 { | |
418 throw new IllegalStateException("State==HEADER"); | |
419 } | |
420 | |
421 if (_contentLength >= 0 && _contentLength != _contentWritten && !_head) | |
422 { | |
423 if (LOG.isDebugEnabled()) | |
424 LOG.debug("ContentLength written=="+_contentWritten+" != contentLength=="+_contentLength); | |
425 _persistent = false; | |
426 } | |
427 } | |
428 | |
429 /* ------------------------------------------------------------ */ | |
430 public abstract int flushBuffer() throws IOException; | |
431 | |
432 | |
433 /* ------------------------------------------------------------ */ | |
434 public void flush(long maxIdleTime) throws IOException | |
435 { | |
436 // block until everything is flushed | |
437 long now=System.currentTimeMillis(); | |
438 long end=now+maxIdleTime; | |
439 Buffer content = _content; | |
440 Buffer buffer = _buffer; | |
441 if (content!=null && content.length()>0 || buffer!=null && buffer.length()>0 || isBufferFull()) | |
442 { | |
443 flushBuffer(); | |
444 | |
445 while (now<end && (content!=null && content.length()>0 ||buffer!=null && buffer.length()>0) && _endp.isOpen()&& !_endp.isOutputShutdown()) | |
446 { | |
447 blockForOutput(end-now); | |
448 now=System.currentTimeMillis(); | |
449 } | |
450 } | |
451 } | |
452 | |
453 /* ------------------------------------------------------------ */ | |
454 /** | |
455 * Utility method to send an error response. If the builder is not committed, this call is | |
456 * equivalent to a setResponse, addContent and complete call. | |
457 * | |
458 * @param code The error code | |
459 * @param reason The error reason | |
460 * @param content Contents of the error page | |
461 * @param close True if the connection should be closed | |
462 * @throws IOException if there is a problem flushing the response | |
463 */ | |
464 public void sendError(int code, String reason, String content, boolean close) throws IOException | |
465 { | |
466 if (close) | |
467 _persistent=false; | |
468 if (isCommitted()) | |
469 { | |
470 LOG.debug("sendError on committed: {} {}",code,reason); | |
471 } | |
472 else | |
473 { | |
474 LOG.debug("sendError: {} {}",code,reason); | |
475 setResponse(code, reason); | |
476 if (content != null) | |
477 { | |
478 completeHeader(null, false); | |
479 addContent(new View(new ByteArrayBuffer(content)), Generator.LAST); | |
480 } | |
481 else if (code>=400) | |
482 { | |
483 completeHeader(null, false); | |
484 addContent(new View(new ByteArrayBuffer("Error: "+(reason==null?(""+code):reason))), Generator.LAST); | |
485 } | |
486 else | |
487 { | |
488 completeHeader(null, true); | |
489 } | |
490 complete(); | |
491 } | |
492 } | |
493 | |
494 /* ------------------------------------------------------------ */ | |
495 /** | |
496 * @return Returns the contentWritten. | |
497 */ | |
498 public long getContentWritten() | |
499 { | |
500 return _contentWritten; | |
501 } | |
502 | |
503 | |
504 | |
505 /* ------------------------------------------------------------ */ | |
506 public void blockForOutput(long maxIdleTime) throws IOException | |
507 { | |
508 if (_endp.isBlocking()) | |
509 { | |
510 try | |
511 { | |
512 flushBuffer(); | |
513 } | |
514 catch(IOException e) | |
515 { | |
516 _endp.close(); | |
517 throw e; | |
518 } | |
519 } | |
520 else | |
521 { | |
522 if (!_endp.blockWritable(maxIdleTime)) | |
523 { | |
524 _endp.close(); | |
525 throw new EofException("timeout"); | |
526 } | |
527 | |
528 flushBuffer(); | |
529 } | |
530 } | |
531 | |
532 } |