Mercurial Hosting > luan
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 } |