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 } |
