comparison src/org/eclipse/jetty/http/HttpGenerator.java @ 1057:afc9610dc12e

remove AbstractGenerator
author Franklin Schmidt <fschmidt@gmail.com>
date Tue, 08 Nov 2016 04:05:04 -0700
parents 2b769da7f67d
children 419bf9c03d84
comparison
equal deleted inserted replaced
1056:7d872cc72ec2 1057:afc9610dc12e
37 * HttpGenerator. Builds HTTP Messages. 37 * HttpGenerator. Builds HTTP Messages.
38 * 38 *
39 * 39 *
40 * 40 *
41 */ 41 */
42 public final class HttpGenerator extends AbstractGenerator 42 public final class HttpGenerator
43 { 43 {
44 private static final Logger LOG = LoggerFactory.getLogger(HttpGenerator.class); 44 private static final Logger LOG = LoggerFactory.getLogger(HttpGenerator.class);
45 45
46 // Build cache of response lines for status 46 // Build cache of response lines for status
47 private static class Status 47 private static class Status
99 private boolean _needCRLF = false; 99 private boolean _needCRLF = false;
100 private boolean _needEOC = false; 100 private boolean _needEOC = false;
101 private boolean _bufferChunked = false; 101 private boolean _bufferChunked = false;
102 102
103 103
104 public HttpGenerator(Buffers buffers, EndPoint io)
105 {
106 super(buffers,io);
107 }
108
109 public void shutdown() { 104 public void shutdown() {
110 if (_persistent!=null && !_persistent && _endp!=null && !_endp.isOutputShutdown()) 105 if (_persistent!=null && !_persistent && _endp!=null && !_endp.isOutputShutdown())
111 { 106 {
112 try 107 try
113 { 108 {
233 return Integer.MAX_VALUE; 228 return Integer.MAX_VALUE;
234 229
235 return _buffer.space()-(_contentLength == HttpTokens.CHUNKED_CONTENT?CHUNK_SPACE:0); 230 return _buffer.space()-(_contentLength == HttpTokens.CHUNKED_CONTENT?CHUNK_SPACE:0);
236 } 231 }
237 232
238 @Override
239 public boolean isBufferFull() 233 public boolean isBufferFull()
240 { 234 {
241 // Should we flush the buffers? 235 // Should we flush the buffers?
242 return super.isBufferFull() || _bufferChunked || _bypass || (_contentLength == HttpTokens.CHUNKED_CONTENT && _buffer != null && _buffer.space() < CHUNK_SPACE); 236 return isBufferFull2() || _bufferChunked || _bypass || (_contentLength == HttpTokens.CHUNKED_CONTENT && _buffer != null && _buffer.space() < CHUNK_SPACE);
243 } 237 }
244 238
245 public void send1xx(int code) throws IOException 239 public void send1xx(int code) throws IOException
246 { 240 {
247 if (_state != STATE_HEADER) 241 if (_state != STATE_HEADER)
277 LOG.debug("",e); 271 LOG.debug("",e);
278 throw new InterruptedIOException(e.toString()); 272 throw new InterruptedIOException(e.toString());
279 } 273 }
280 } 274 }
281 275
282 @Override
283 boolean isRequest() 276 boolean isRequest()
284 { 277 {
285 return _method!=null; 278 return _method!=null;
286 } 279 }
287 280
288 private boolean isResponse() 281 private boolean isResponse()
289 { 282 {
290 return _method==null; 283 return _method==null;
291 } 284 }
292 285
293 @Override
294 public void completeHeader(HttpFields fields, boolean allContentAdded) throws IOException 286 public void completeHeader(HttpFields fields, boolean allContentAdded) throws IOException
295 { 287 {
296 if (_state != STATE_HEADER) 288 if (_state != STATE_HEADER)
297 return; 289 return;
298 290
699 /** 691 /**
700 * Complete the message. 692 * Complete the message.
701 * 693 *
702 * @throws IOException 694 * @throws IOException
703 */ 695 */
704 @Override
705 public void complete() throws IOException 696 public void complete() throws IOException
706 { 697 {
707 if (_state == STATE_END) 698 if (_state == STATE_END)
708 return; 699 return;
709 700
710 super.complete(); 701 complete2();
711 702
712 if (_state < STATE_FLUSHING) 703 if (_state < STATE_FLUSHING)
713 { 704 {
714 _state = STATE_FLUSHING; 705 _state = STATE_FLUSHING;
715 if (_contentLength == HttpTokens.CHUNKED_CONTENT) 706 if (_contentLength == HttpTokens.CHUNKED_CONTENT)
717 } 708 }
718 709
719 flushBuffer(); 710 flushBuffer();
720 } 711 }
721 712
722 @Override
723 public int flushBuffer() throws IOException 713 public int flushBuffer() throws IOException
724 { 714 {
725 try 715 try
726 { 716 {
727 717
991 _state, 981 _state,
992 header == null ? -1 : header.remaining(), 982 header == null ? -1 : header.remaining(),
993 buffer == null ? -1 : buffer.remaining(), 983 buffer == null ? -1 : buffer.remaining(),
994 content == null ? -1 : content.remaining()); 984 content == null ? -1 : content.remaining());
995 } 985 }
986
987
988
989
990
991
992
993
994
995
996
997
998 // AbstractGenerator
999
1000 public static final boolean LAST=true;
1001 public static final boolean MORE=false;
1002
1003 // states
1004 private final static int STATE_HEADER = 0;
1005 private final static int STATE_CONTENT = 2;
1006 private final static int STATE_FLUSHING = 3;
1007 private final static int STATE_END = 4;
1008
1009 // data
1010
1011 private final Buffers _buffers; // source of buffers
1012 private final EndPoint _endp;
1013
1014 private int _state = STATE_HEADER;
1015
1016 private int _status = 0;
1017 private int _version = HttpVersions.HTTP_1_1_ORDINAL;
1018 private JBuffer _reason;
1019 private JBuffer _method;
1020 private String _uri;
1021
1022 private long _contentWritten = 0;
1023 private long _contentLength = HttpTokens.UNKNOWN_CONTENT;
1024 private boolean _last = false;
1025 private boolean _head = false;
1026 private boolean _noContent = false;
1027 private Boolean _persistent = null;
1028
1029 private JBuffer _header; // JBuffer for HTTP header (and maybe small _content)
1030 private JBuffer _buffer; // JBuffer for copy of passed _content
1031 private JBuffer _content; // JBuffer passed to addContent
1032
1033
1034 public HttpGenerator(Buffers buffers, EndPoint io)
1035 {
1036 this._buffers = buffers;
1037 this._endp = io;
1038 }
1039
1040 public final boolean isOpen()
1041 {
1042 return _endp.isOpen();
1043 }
1044
1045 public final void resetBuffer()
1046 {
1047 if(_state>=STATE_FLUSHING)
1048 throw new IllegalStateException("Flushed");
1049
1050 _last = false;
1051 _persistent = null;
1052 _contentWritten = 0;
1053 _contentLength = HttpTokens.UNKNOWN_CONTENT;
1054 _content=null;
1055 if (_buffer!=null)
1056 _buffer.clear();
1057 }
1058
1059 /* ------------------------------------------------------------ */
1060 /**
1061 * @return Returns the contentBufferSize.
1062 */
1063 public final int getContentBufferSize()
1064 {
1065 if (_buffer==null)
1066 _buffer = _buffers.getBuffer();
1067 return _buffer.capacity();
1068 }
1069
1070 public final JBuffer getUncheckedBuffer()
1071 {
1072 return _buffer;
1073 }
1074
1075 public final boolean isComplete()
1076 {
1077 return _state == STATE_END;
1078 }
1079
1080 public final boolean isIdle()
1081 {
1082 return _state == STATE_HEADER && _method==null && _status==0;
1083 }
1084
1085 public final boolean isCommitted()
1086 {
1087 return _state != STATE_HEADER;
1088 }
1089
1090 public final void setContentLength(long value)
1091 {
1092 if (value<0)
1093 _contentLength=HttpTokens.UNKNOWN_CONTENT;
1094 else
1095 _contentLength=value;
1096 }
1097
1098 public final void setHead(boolean head)
1099 {
1100 _head = head;
1101 }
1102
1103 /* ------------------------------------------------------------ */
1104 /**
1105 * @return <code>false</code> if the connection should be closed after a request has been read,
1106 * <code>true</code> if it should be used for additional requests.
1107 */
1108 public final boolean isPersistent()
1109 {
1110 return _persistent!=null
1111 ?_persistent.booleanValue()
1112 :(isRequest()?true:_version>HttpVersions.HTTP_1_0_ORDINAL);
1113 }
1114
1115 public final void setPersistent(boolean persistent)
1116 {
1117 _persistent = persistent;
1118 }
1119
1120 /* ------------------------------------------------------------ */
1121 /**
1122 * @param version The version of the client the response is being sent to (NB. Not the version
1123 * in the response, which is the version of the server).
1124 */
1125 public final void setVersion(int version)
1126 {
1127 if (_state != STATE_HEADER)
1128 throw new IllegalStateException("STATE!=START "+_state);
1129 _version = version;
1130 if (_version==HttpVersions.HTTP_0_9_ORDINAL && _method!=null)
1131 _noContent=true;
1132 }
1133
1134 /* ------------------------------------------------------------ */
1135 /**
1136 * @param status The status code to send.
1137 * @param reason the status message to send.
1138 */
1139 public final void setResponse(int status, String reason)
1140 {
1141 if (_state != STATE_HEADER) throw new IllegalStateException("STATE!=START");
1142 _method=null;
1143 _status = status;
1144 if (reason!=null)
1145 {
1146 int len=reason.length();
1147
1148 // TODO don't hard code
1149 if (len>1024)
1150 len=1024;
1151 _reason = BufferUtil.newBuffer(len);
1152 for (int i=0;i<len;i++)
1153 {
1154 char ch = reason.charAt(i);
1155 if (ch!='\r'&&ch!='\n')
1156 _reason.put((byte)ch);
1157 else
1158 _reason.put((byte)' ');
1159 }
1160 }
1161 }
1162
1163 public final void completeUncheckedAddContent()
1164 {
1165 if (_noContent)
1166 {
1167 if(_buffer!=null)
1168 _buffer.clear();
1169 }
1170 else
1171 {
1172 _contentWritten+=_buffer.remaining();
1173 if (_head)
1174 _buffer.clear();
1175 }
1176 }
1177
1178 private boolean isBufferFull2()
1179 {
1180 if (_buffer != null && _buffer.space()==0)
1181 {
1182 if (_buffer.remaining()==0)
1183 _buffer.compact();
1184 return _buffer.space()==0;
1185 }
1186
1187 return _content!=null && _content.remaining()>0;
1188 }
1189
1190 public final boolean isWritten()
1191 {
1192 return _contentWritten>0;
1193 }
1194
1195 public final boolean isAllContentWritten()
1196 {
1197 return _contentLength>=0 && _contentWritten>=_contentLength;
1198 }
1199
1200
1201 private void complete2() throws IOException
1202 {
1203 if (_state == STATE_HEADER)
1204 {
1205 throw new IllegalStateException("State==HEADER");
1206 }
1207
1208 if (_contentLength >= 0 && _contentLength != _contentWritten && !_head)
1209 {
1210 if (LOG.isDebugEnabled())
1211 LOG.debug("ContentLength written=="+_contentWritten+" != contentLength=="+_contentLength);
1212 _persistent = false;
1213 }
1214 }
1215
1216
1217 public final void flush(long maxIdleTime) throws IOException
1218 {
1219 // block until everything is flushed
1220 long now=System.currentTimeMillis();
1221 long end=now+maxIdleTime;
1222 JBuffer content = _content;
1223 JBuffer buffer = _buffer;
1224 if (content!=null && content.remaining()>0 || buffer!=null && buffer.remaining()>0 || isBufferFull())
1225 {
1226 flushBuffer();
1227
1228 while (now<end && (content!=null && content.remaining()>0 ||buffer!=null && buffer.remaining()>0) && _endp.isOpen()&& !_endp.isOutputShutdown())
1229 {
1230 blockForOutput(end-now);
1231 now=System.currentTimeMillis();
1232 }
1233 }
1234 }
1235
1236 /* ------------------------------------------------------------ */
1237 /**
1238 * Utility method to send an error response. If the builder is not committed, this call is
1239 * equivalent to a setResponse, addContent and complete call.
1240 *
1241 * @param code The error code
1242 * @param reason The error reason
1243 * @param content Contents of the error page
1244 * @param close True if the connection should be closed
1245 * @throws IOException if there is a problem flushing the response
1246 */
1247 public final void sendError(int code, String reason, String content, boolean close) throws IOException
1248 {
1249 if (close)
1250 _persistent=false;
1251 if (isCommitted())
1252 {
1253 LOG.debug("sendError on committed: {} {}",code,reason);
1254 }
1255 else
1256 {
1257 LOG.debug("sendError: {} {}",code,reason);
1258 setResponse(code, reason);
1259 if (content != null)
1260 {
1261 completeHeader(null, false);
1262 addContent(BufferUtil.wrap(content), LAST);
1263 }
1264 else if (code>=400)
1265 {
1266 completeHeader(null, false);
1267 addContent(BufferUtil.wrap("Error: "+(reason==null?(""+code):reason)), LAST);
1268 }
1269 else
1270 {
1271 completeHeader(null, true);
1272 }
1273 complete();
1274 }
1275 }
1276
1277 public final long getContentWritten()
1278 {
1279 return _contentWritten;
1280 }
1281
1282
1283 public final void blockForOutput(long maxIdleTime) throws IOException
1284 {
1285 if (_endp.isBlocking())
1286 {
1287 try
1288 {
1289 flushBuffer();
1290 }
1291 catch(IOException e)
1292 {
1293 _endp.close();
1294 throw e;
1295 }
1296 }
1297 else
1298 {
1299 if (!_endp.blockWritable(maxIdleTime))
1300 {
1301 _endp.close();
1302 throw new EofException("timeout");
1303 }
1304
1305 flushBuffer();
1306 }
1307 }
1308
996 } 1309 }