1
17 package org.apache.coyote.http11;
18
19 import java.io.IOException;
20 import java.io.InterruptedIOException;
21 import java.nio.ByteBuffer;
22 import java.util.ArrayList;
23 import java.util.HashSet;
24 import java.util.List;
25 import java.util.Set;
26 import java.util.regex.Pattern;
27
28 import javax.servlet.http.HttpServletResponse;
29
30 import org.apache.coyote.AbstractProcessor;
31 import org.apache.coyote.ActionCode;
32 import org.apache.coyote.Adapter;
33 import org.apache.coyote.ErrorState;
34 import org.apache.coyote.Request;
35 import org.apache.coyote.RequestInfo;
36 import org.apache.coyote.UpgradeProtocol;
37 import org.apache.coyote.UpgradeToken;
38 import org.apache.coyote.http11.filters.BufferedInputFilter;
39 import org.apache.coyote.http11.filters.ChunkedInputFilter;
40 import org.apache.coyote.http11.filters.ChunkedOutputFilter;
41 import org.apache.coyote.http11.filters.GzipOutputFilter;
42 import org.apache.coyote.http11.filters.IdentityInputFilter;
43 import org.apache.coyote.http11.filters.IdentityOutputFilter;
44 import org.apache.coyote.http11.filters.SavedRequestInputFilter;
45 import org.apache.coyote.http11.filters.VoidInputFilter;
46 import org.apache.coyote.http11.filters.VoidOutputFilter;
47 import org.apache.coyote.http11.upgrade.InternalHttpUpgradeHandler;
48 import org.apache.juli.logging.Log;
49 import org.apache.juli.logging.LogFactory;
50 import org.apache.tomcat.util.ExceptionUtils;
51 import org.apache.tomcat.util.buf.ByteChunk;
52 import org.apache.tomcat.util.buf.MessageBytes;
53 import org.apache.tomcat.util.http.FastHttpDateFormat;
54 import org.apache.tomcat.util.http.MimeHeaders;
55 import org.apache.tomcat.util.http.parser.HttpParser;
56 import org.apache.tomcat.util.http.parser.TokenList;
57 import org.apache.tomcat.util.log.UserDataHelper;
58 import org.apache.tomcat.util.net.AbstractEndpoint.Handler.SocketState;
59 import org.apache.tomcat.util.net.SSLSupport;
60 import org.apache.tomcat.util.net.SendfileDataBase;
61 import org.apache.tomcat.util.net.SendfileKeepAliveState;
62 import org.apache.tomcat.util.net.SendfileState;
63 import org.apache.tomcat.util.net.SocketWrapperBase;
64 import org.apache.tomcat.util.res.StringManager;
65
66 public class Http11Processor extends AbstractProcessor {
67
68 private static final Log log = LogFactory.getLog(Http11Processor.class);
69
70
73 private static final StringManager sm = StringManager.getManager(Http11Processor.class);
74
75
76 private final AbstractHttp11Protocol<?> protocol;
77
78
79
82 private final Http11InputBuffer inputBuffer;
83
84
85
88 private final Http11OutputBuffer outputBuffer;
89
90
91 private final HttpParser httpParser;
92
93
94
98 private int pluggableFilterIndex = Integer.MAX_VALUE;
99
100
101
104 private volatile boolean keepAlive = true;
105
106
107
111 private boolean openSocket = false;
112
113
114
117 private boolean readComplete = true;
118
119
122 private boolean http11 = true;
123
124
125
128 private boolean http09 = false;
129
130
131
135 private boolean contentDelimitation = true;
136
137
138
142 private UpgradeToken upgradeToken = null;
143
144
145
148 private SendfileDataBase sendfileData = null;
149
150
151 public Http11Processor(AbstractHttp11Protocol<?> protocol, Adapter adapter) {
152 super(adapter);
153 this.protocol = protocol;
154
155 httpParser = new HttpParser(protocol.getRelaxedPathChars(),
156 protocol.getRelaxedQueryChars());
157
158 inputBuffer = new Http11InputBuffer(request, protocol.getMaxHttpHeaderSize(),
159 protocol.getRejectIllegalHeader(), httpParser);
160 request.setInputBuffer(inputBuffer);
161
162 outputBuffer = new Http11OutputBuffer(response, protocol.getMaxHttpHeaderSize());
163 response.setOutputBuffer(outputBuffer);
164
165
166 inputBuffer.addFilter(new IdentityInputFilter(protocol.getMaxSwallowSize()));
167 outputBuffer.addFilter(new IdentityOutputFilter());
168
169
170 inputBuffer.addFilter(new ChunkedInputFilter(protocol.getMaxTrailerSize(),
171 protocol.getAllowedTrailerHeadersInternal(), protocol.getMaxExtensionSize(),
172 protocol.getMaxSwallowSize()));
173 outputBuffer.addFilter(new ChunkedOutputFilter());
174
175
176 inputBuffer.addFilter(new VoidInputFilter());
177 outputBuffer.addFilter(new VoidOutputFilter());
178
179
180 inputBuffer.addFilter(new BufferedInputFilter());
181
182
183
184 outputBuffer.addFilter(new GzipOutputFilter());
185
186 pluggableFilterIndex = inputBuffer.getFilters().length;
187 }
188
189
190
194 private static boolean statusDropsConnection(int status) {
195 return status == 400 ||
196 status == 408 ||
197 status == 411 ||
198 status == 413 ||
199 status == 414 ||
200 status == 500 ||
201 status == 503 ||
202 status == 501 ;
203 }
204
205
206
210 private void addInputFilter(InputFilter[] inputFilters, String encodingName) {
211
212
213
214 if (encodingName.equals("identity")) {
215
216 } else if (encodingName.equals("chunked")) {
217 inputBuffer.addActiveFilter
218 (inputFilters[Constants.CHUNKED_FILTER]);
219 contentDelimitation = true;
220 } else {
221 for (int i = pluggableFilterIndex; i < inputFilters.length; i++) {
222 if (inputFilters[i].getEncodingName().toString().equals(encodingName)) {
223 inputBuffer.addActiveFilter(inputFilters[i]);
224 return;
225 }
226 }
227
228
229 response.setStatus(501);
230 setErrorState(ErrorState.CLOSE_CLEAN, null);
231 if (log.isDebugEnabled()) {
232 log.debug(sm.getString("http11processor.request.prepare") +
233 " Unsupported transfer encoding [" + encodingName + "]");
234 }
235 }
236 }
237
238
239 @Override
240 public SocketState service(SocketWrapperBase<?> socketWrapper)
241 throws IOException {
242 RequestInfo rp = request.getRequestProcessor();
243 rp.setStage(org.apache.coyote.Constants.STAGE_PARSE);
244
245
246 setSocketWrapper(socketWrapper);
247
248
249 keepAlive = true;
250 openSocket = false;
251 readComplete = true;
252 boolean keptAlive = false;
253 SendfileState sendfileState = SendfileState.DONE;
254
255 while (!getErrorState().isError() && keepAlive && !isAsync() && upgradeToken == null &&
256 sendfileState == SendfileState.DONE && !protocol.isPaused()) {
257
258
259 try {
260 if (!inputBuffer.parseRequestLine(keptAlive, protocol.getConnectionTimeout(),
261 protocol.getKeepAliveTimeout())) {
262 if (inputBuffer.getParsingRequestLinePhase() == -1) {
263 return SocketState.UPGRADING;
264 } else if (handleIncompleteRequestLineRead()) {
265 break;
266 }
267 }
268
269
270
271
272 prepareRequestProtocol();
273
274 if (protocol.isPaused()) {
275
276 response.setStatus(503);
277 setErrorState(ErrorState.CLOSE_CLEAN, null);
278 } else {
279 keptAlive = true;
280
281 request.getMimeHeaders().setLimit(protocol.getMaxHeaderCount());
282
283 if (!http09 && !inputBuffer.parseHeaders()) {
284
285
286 openSocket = true;
287 readComplete = false;
288 break;
289 }
290 if (!protocol.getDisableUploadTimeout()) {
291 socketWrapper.setReadTimeout(protocol.getConnectionUploadTimeout());
292 }
293 }
294 } catch (IOException e) {
295 if (log.isDebugEnabled()) {
296 log.debug(sm.getString("http11processor.header.parse"), e);
297 }
298 setErrorState(ErrorState.CLOSE_CONNECTION_NOW, e);
299 break;
300 } catch (Throwable t) {
301 ExceptionUtils.handleThrowable(t);
302 UserDataHelper.Mode logMode = userDataHelper.getNextMode();
303 if (logMode != null) {
304 String message = sm.getString("http11processor.header.parse");
305 switch (logMode) {
306 case INFO_THEN_DEBUG:
307 message += sm.getString("http11processor.fallToDebug");
308
309 case INFO:
310 log.info(message, t);
311 break;
312 case DEBUG:
313 log.debug(message, t);
314 }
315 }
316
317 response.setStatus(400);
318 setErrorState(ErrorState.CLOSE_CLEAN, t);
319 }
320
321
322 if (isConnectionToken(request.getMimeHeaders(), "upgrade")) {
323
324 String requestedProtocol = request.getHeader("Upgrade");
325
326 UpgradeProtocol upgradeProtocol = protocol.getUpgradeProtocol(requestedProtocol);
327 if (upgradeProtocol != null) {
328 if (upgradeProtocol.accept(request)) {
329 response.setStatus(HttpServletResponse.SC_SWITCHING_PROTOCOLS);
330 response.setHeader("Connection", "Upgrade");
331 response.setHeader("Upgrade", requestedProtocol);
332 action(ActionCode.CLOSE, null);
333 getAdapter().log(request, response, 0);
334
335 InternalHttpUpgradeHandler upgradeHandler =
336 upgradeProtocol.getInternalUpgradeHandler(
337 socketWrapper, getAdapter(), cloneRequest(request));
338 UpgradeToken upgradeToken = new UpgradeToken(upgradeHandler, null, null);
339 action(ActionCode.UPGRADE, upgradeToken);
340 return SocketState.UPGRADING;
341 }
342 }
343 }
344
345 if (getErrorState().isIoAllowed()) {
346
347 rp.setStage(org.apache.coyote.Constants.STAGE_PREPARE);
348 try {
349 prepareRequest();
350 } catch (Throwable t) {
351 ExceptionUtils.handleThrowable(t);
352 if (log.isDebugEnabled()) {
353 log.debug(sm.getString("http11processor.request.prepare"), t);
354 }
355
356 response.setStatus(500);
357 setErrorState(ErrorState.CLOSE_CLEAN, t);
358 }
359 }
360
361 int maxKeepAliveRequests = protocol.getMaxKeepAliveRequests();
362 if (maxKeepAliveRequests == 1) {
363 keepAlive = false;
364 } else if (maxKeepAliveRequests > 0 &&
365 socketWrapper.decrementKeepAlive() <= 0) {
366 keepAlive = false;
367 }
368
369
370 if (getErrorState().isIoAllowed()) {
371 try {
372 rp.setStage(org.apache.coyote.Constants.STAGE_SERVICE);
373 getAdapter().service(request, response);
374
375
376
377
378
379 if(keepAlive && !getErrorState().isError() && !isAsync() &&
380 statusDropsConnection(response.getStatus())) {
381 setErrorState(ErrorState.CLOSE_CLEAN, null);
382 }
383 } catch (InterruptedIOException e) {
384 setErrorState(ErrorState.CLOSE_CONNECTION_NOW, e);
385 } catch (HeadersTooLargeException e) {
386 log.error(sm.getString("http11processor.request.process"), e);
387
388
389 if (response.isCommitted()) {
390 setErrorState(ErrorState.CLOSE_NOW, e);
391 } else {
392 response.reset();
393 response.setStatus(500);
394 setErrorState(ErrorState.CLOSE_CLEAN, e);
395 response.setHeader("Connection", "close");
396 }
397 } catch (Throwable t) {
398 ExceptionUtils.handleThrowable(t);
399 log.error(sm.getString("http11processor.request.process"), t);
400
401 response.setStatus(500);
402 setErrorState(ErrorState.CLOSE_CLEAN, t);
403 getAdapter().log(request, response, 0);
404 }
405 }
406
407
408 rp.setStage(org.apache.coyote.Constants.STAGE_ENDINPUT);
409 if (!isAsync()) {
410
411
412
413 endRequest();
414 }
415 rp.setStage(org.apache.coyote.Constants.STAGE_ENDOUTPUT);
416
417
418
419 if (getErrorState().isError()) {
420 response.setStatus(500);
421 }
422
423 if (!isAsync() || getErrorState().isError()) {
424 request.updateCounters();
425 if (getErrorState().isIoAllowed()) {
426 inputBuffer.nextRequest();
427 outputBuffer.nextRequest();
428 }
429 }
430
431 if (!protocol.getDisableUploadTimeout()) {
432 int connectionTimeout = protocol.getConnectionTimeout();
433 if(connectionTimeout > 0) {
434 socketWrapper.setReadTimeout(connectionTimeout);
435 } else {
436 socketWrapper.setReadTimeout(0);
437 }
438 }
439
440 rp.setStage(org.apache.coyote.Constants.STAGE_KEEPALIVE);
441
442 sendfileState = processSendfile(socketWrapper);
443 }
444
445 rp.setStage(org.apache.coyote.Constants.STAGE_ENDED);
446
447 if (getErrorState().isError() || (protocol.isPaused() && !isAsync())) {
448 return SocketState.CLOSED;
449 } else if (isAsync()) {
450 return SocketState.LONG;
451 } else if (isUpgrade()) {
452 return SocketState.UPGRADING;
453 } else {
454 if (sendfileState == SendfileState.PENDING) {
455 return SocketState.SENDFILE;
456 } else {
457 if (openSocket) {
458 if (readComplete) {
459 return SocketState.OPEN;
460 } else {
461 return SocketState.LONG;
462 }
463 } else {
464 return SocketState.CLOSED;
465 }
466 }
467 }
468 }
469
470
471 @Override
472 protected final void setSocketWrapper(SocketWrapperBase<?> socketWrapper) {
473 super.setSocketWrapper(socketWrapper);
474 inputBuffer.init(socketWrapper);
475 outputBuffer.init(socketWrapper);
476 }
477
478
479 private Request cloneRequest(Request source) throws IOException {
480 Request dest = new Request();
481
482
483
484
485 dest.decodedURI().duplicate(source.decodedURI());
486 dest.method().duplicate(source.method());
487 dest.getMimeHeaders().duplicate(source.getMimeHeaders());
488 dest.requestURI().duplicate(source.requestURI());
489 dest.queryString().duplicate(source.queryString());
490
491 return dest;
492
493 }
494 private boolean handleIncompleteRequestLineRead() {
495
496
497 openSocket = true;
498
499 if (inputBuffer.getParsingRequestLinePhase() > 1) {
500
501 if (protocol.isPaused()) {
502
503 response.setStatus(503);
504 setErrorState(ErrorState.CLOSE_CLEAN, null);
505 return false;
506 } else {
507
508 readComplete = false;
509 }
510 }
511 return true;
512 }
513
514
515 private void checkExpectationAndResponseStatus() {
516 if (request.hasExpectation() &&
517 (response.getStatus() < 200 || response.getStatus() > 299)) {
518
519
520
521
522
523
524 inputBuffer.setSwallowInput(false);
525 keepAlive = false;
526 }
527 }
528
529
530 private void prepareRequestProtocol() {
531
532 MessageBytes protocolMB = request.protocol();
533 if (protocolMB.equals(Constants.HTTP_11)) {
534 http09 = false;
535 http11 = true;
536 protocolMB.setString(Constants.HTTP_11);
537 } else if (protocolMB.equals(Constants.HTTP_10)) {
538 http09 = false;
539 http11 = false;
540 keepAlive = false;
541 protocolMB.setString(Constants.HTTP_10);
542 } else if (protocolMB.equals("")) {
543
544 http09 = true;
545 http11 = false;
546 keepAlive = false;
547 } else {
548
549 http09 = false;
550 http11 = false;
551
552 response.setStatus(505);
553 setErrorState(ErrorState.CLOSE_CLEAN, null);
554 if (log.isDebugEnabled()) {
555 log.debug(sm.getString("http11processor.request.prepare")+
556 " Unsupported HTTP version \""+protocolMB+"\"");
557 }
558 }
559 }
560
561
562
565 private void prepareRequest() throws IOException {
566
567 contentDelimitation = false;
568
569 if (protocol.isSSLEnabled()) {
570 request.scheme().setString("https");
571 }
572
573 MimeHeaders headers = request.getMimeHeaders();
574
575
576 MessageBytes connectionValueMB = headers.getValue(Constants.CONNECTION);
577 if (connectionValueMB != null && !connectionValueMB.isNull()) {
578 Set<String> tokens = new HashSet<>();
579 TokenList.parseTokenList(headers.values(Constants.CONNECTION), tokens);
580 if (tokens.contains(Constants.CLOSE)) {
581 keepAlive = false;
582 } else if (tokens.contains(Constants.KEEP_ALIVE_HEADER_VALUE_TOKEN)) {
583 keepAlive = true;
584 }
585 }
586
587 if (http11) {
588 MessageBytes expectMB = headers.getValue("expect");
589 if (expectMB != null && !expectMB.isNull()) {
590 if (expectMB.toString().trim().equalsIgnoreCase("100-continue")) {
591 inputBuffer.setSwallowInput(false);
592 request.setExpectation(true);
593 } else {
594 response.setStatus(HttpServletResponse.SC_EXPECTATION_FAILED);
595 setErrorState(ErrorState.CLOSE_CLEAN, null);
596 }
597 }
598 }
599
600
601 Pattern restrictedUserAgents = protocol.getRestrictedUserAgentsPattern();
602 if (restrictedUserAgents != null && (http11 || keepAlive)) {
603 MessageBytes userAgentValueMB = headers.getValue("user-agent");
604
605
606 if(userAgentValueMB != null && !userAgentValueMB.isNull()) {
607 String userAgentValue = userAgentValueMB.toString();
608 if (restrictedUserAgents.matcher(userAgentValue).matches()) {
609 http11 = false;
610 keepAlive = false;
611 }
612 }
613 }
614
615
616
617 MessageBytes hostValueMB = null;
618 try {
619 hostValueMB = headers.getUniqueValue("host");
620 } catch (IllegalArgumentException iae) {
621
622 badRequest("http11processor.request.multipleHosts");
623 }
624 if (http11 && hostValueMB == null) {
625 badRequest("http11processor.request.noHostHeader");
626 }
627
628
629
630 ByteChunk uriBC = request.requestURI().getByteChunk();
631 byte[] uriB = uriBC.getBytes();
632 if (uriBC.startsWithIgnoreCase("http", 0)) {
633 int pos = 4;
634
635 if (uriBC.startsWithIgnoreCase("s", pos)) {
636 pos++;
637 }
638
639 if (uriBC.startsWith(":, pos)) {
640 pos += 3;
641 int uriBCStart = uriBC.getStart();
642
643
644
645 int slashPos = uriBC.indexOf('/', pos);
646
647 int atPos = uriBC.indexOf('@', pos);
648 if (slashPos > -1 && atPos > slashPos) {
649
650 atPos = -1;
651 }
652
653 if (slashPos == -1) {
654 slashPos = uriBC.getLength();
655
656
657
658
659 request.requestURI().setBytes(uriB, uriBCStart + 6, 1);
660 } else {
661 request.requestURI().setBytes(uriB, uriBCStart + slashPos, uriBC.getLength() - slashPos);
662 }
663
664
665 if (atPos != -1) {
666
667 for (; pos < atPos; pos++) {
668 byte c = uriB[uriBCStart + pos];
669 if (!HttpParser.isUserInfo(c)) {
670
671
672
673 badRequest("http11processor.request.invalidUserInfo");
674 break;
675 }
676 }
677
678 pos = atPos + 1;
679 }
680
681 if (http11) {
682
683 if (hostValueMB != null) {
684
685
686 if (!hostValueMB.getByteChunk().equals(
687 uriB, uriBCStart + pos, slashPos - pos)) {
688 if (protocol.getAllowHostHeaderMismatch()) {
689
690
691
692
693 hostValueMB = headers.setValue("host");
694 hostValueMB.setBytes(uriB, uriBCStart + pos, slashPos - pos);
695 } else {
696
697
698
699 badRequest("http11processor.request.inconsistentHosts");
700 }
701 }
702 }
703 } else {
704
705
706 try {
707 hostValueMB = headers.setValue("host");
708 hostValueMB.setBytes(uriB, uriBCStart + pos, slashPos - pos);
709 } catch (IllegalStateException e) {
710
711
712
713
714
715 }
716 }
717 } else {
718 badRequest("http11processor.request.invalidScheme");
719 }
720 }
721
722
723
724 for (int i = uriBC.getStart(); i < uriBC.getEnd(); i++) {
725 if (!httpParser.isAbsolutePathRelaxed(uriB[i])) {
726 badRequest("http11processor.request.invalidUri");
727 break;
728 }
729 }
730
731
732 InputFilter[] inputFilters = inputBuffer.getFilters();
733
734
735 if (http11) {
736 MessageBytes transferEncodingValueMB = headers.getValue("transfer-encoding");
737 if (transferEncodingValueMB != null) {
738 List<String> encodingNames = new ArrayList<>();
739 if (TokenList.parseTokenList(headers.values("transfer-encoding"), encodingNames)) {
740 for (String encodingName : encodingNames) {
741
742 addInputFilter(inputFilters, encodingName);
743 }
744 } else {
745
746 badRequest("http11processor.request.invalidTransferEncoding");
747 }
748 }
749 }
750
751
752 long contentLength = -1;
753 try {
754 contentLength = request.getContentLengthLong();
755 } catch (NumberFormatException e) {
756 badRequest("http11processor.request.nonNumericContentLength");
757 } catch (IllegalArgumentException e) {
758 badRequest("http11processor.request.multipleContentLength");
759 }
760 if (contentLength >= 0) {
761 if (contentDelimitation) {
762
763
764
765
766
767 headers.removeHeader("content-length");
768 request.setContentLength(-1);
769 } else {
770 inputBuffer.addActiveFilter(inputFilters[Constants.IDENTITY_FILTER]);
771 contentDelimitation = true;
772 }
773 }
774
775
776 parseHost(hostValueMB);
777
778 if (!contentDelimitation) {
779
780
781
782 inputBuffer.addActiveFilter(inputFilters[Constants.VOID_FILTER]);
783 contentDelimitation = true;
784 }
785
786 if (!getErrorState().isIoAllowed()) {
787 getAdapter().log(request, response, 0);
788 }
789 }
790
791
792 private void badRequest(String errorKey) {
793 response.setStatus(400);
794 setErrorState(ErrorState.CLOSE_CLEAN, null);
795 if (log.isDebugEnabled()) {
796 log.debug(sm.getString(errorKey));
797 }
798 }
799
800
801
805 @Override
806 protected final void prepareResponse() throws IOException {
807
808 boolean entityBody = true;
809 contentDelimitation = false;
810
811 OutputFilter[] outputFilters = outputBuffer.getFilters();
812
813 if (http09 == true) {
814
815 outputBuffer.addActiveFilter(outputFilters[Constants.IDENTITY_FILTER]);
816 outputBuffer.commit();
817 return;
818 }
819
820 int statusCode = response.getStatus();
821 if (statusCode < 200 || statusCode == 204 || statusCode == 205 ||
822 statusCode == 304) {
823
824 outputBuffer.addActiveFilter
825 (outputFilters[Constants.VOID_FILTER]);
826 entityBody = false;
827 contentDelimitation = true;
828 if (statusCode == 205) {
829
830
831 response.setContentLength(0);
832 } else {
833 response.setContentLength(-1);
834 }
835 }
836
837 MessageBytes methodMB = request.method();
838 if (methodMB.equals("HEAD")) {
839
840 outputBuffer.addActiveFilter
841 (outputFilters[Constants.VOID_FILTER]);
842 contentDelimitation = true;
843 }
844
845
846 if (protocol.getUseSendfile()) {
847 prepareSendfile(outputFilters);
848 }
849
850
851 boolean useCompression = false;
852 if (entityBody && sendfileData == null) {
853 useCompression = protocol.useCompression(request, response);
854 }
855
856 MimeHeaders headers = response.getMimeHeaders();
857
858 if (entityBody || statusCode == HttpServletResponse.SC_NO_CONTENT) {
859 String contentType = response.getContentType();
860 if (contentType != null) {
861 headers.setValue("Content-Type").setString(contentType);
862 }
863 String contentLanguage = response.getContentLanguage();
864 if (contentLanguage != null) {
865 headers.setValue("Content-Language")
866 .setString(contentLanguage);
867 }
868 }
869
870 long contentLength = response.getContentLengthLong();
871 boolean connectionClosePresent = isConnectionToken(headers, Constants.CLOSE);
872 if (http11 && response.getTrailerFields() != null) {
873
874 outputBuffer.addActiveFilter(outputFilters[Constants.CHUNKED_FILTER]);
875 contentDelimitation = true;
876 headers.addValue(Constants.TRANSFERENCODING).setString(Constants.CHUNKED);
877 } else if (contentLength != -1) {
878 headers.setValue("Content-Length").setLong(contentLength);
879 outputBuffer.addActiveFilter(outputFilters[Constants.IDENTITY_FILTER]);
880 contentDelimitation = true;
881 } else {
882
883
884 if (http11 && entityBody && !connectionClosePresent) {
885 outputBuffer.addActiveFilter(outputFilters[Constants.CHUNKED_FILTER]);
886 contentDelimitation = true;
887 headers.addValue(Constants.TRANSFERENCODING).setString(Constants.CHUNKED);
888 } else {
889 outputBuffer.addActiveFilter(outputFilters[Constants.IDENTITY_FILTER]);
890 }
891 }
892
893 if (useCompression) {
894 outputBuffer.addActiveFilter(outputFilters[Constants.GZIP_FILTER]);
895 }
896
897
898
899 if (headers.getValue("Date") == null) {
900 headers.addValue("Date").setString(
901 FastHttpDateFormat.getCurrentDate());
902 }
903
904
905
906 if ((entityBody) && (!contentDelimitation)) {
907
908
909 keepAlive = false;
910 }
911
912
913
914 checkExpectationAndResponseStatus();
915
916
917
918 if (keepAlive && statusDropsConnection(statusCode)) {
919 keepAlive = false;
920 }
921 if (!keepAlive) {
922
923 if (!connectionClosePresent) {
924 headers.addValue(Constants.CONNECTION).setString(
925 Constants.CLOSE);
926 }
927 } else if (!getErrorState().isError()) {
928 if (!http11) {
929 headers.addValue(Constants.CONNECTION).setString(Constants.KEEP_ALIVE_HEADER_VALUE_TOKEN);
930 }
931
932 if (protocol.getUseKeepAliveResponseHeader()) {
933 boolean connectionKeepAlivePresent =
934 isConnectionToken(request.getMimeHeaders(), Constants.KEEP_ALIVE_HEADER_VALUE_TOKEN);
935
936 if (connectionKeepAlivePresent) {
937 int keepAliveTimeout = protocol.getKeepAliveTimeout();
938
939 if (keepAliveTimeout > 0) {
940 String value = "timeout=" + keepAliveTimeout / 1000L;
941 headers.setValue(Constants.KEEP_ALIVE_HEADER_NAME).setString(value);
942
943 if (http11) {
944
945
946 MessageBytes connectionHeaderValue = headers.getValue(Constants.CONNECTION);
947 if (connectionHeaderValue == null) {
948 headers.addValue(Constants.CONNECTION).setString(Constants.KEEP_ALIVE_HEADER_VALUE_TOKEN);
949 } else {
950 connectionHeaderValue.setString(
951 connectionHeaderValue.getString() + ", " + Constants.KEEP_ALIVE_HEADER_VALUE_TOKEN);
952 }
953 }
954 }
955 }
956 }
957 }
958
959
960 String server = protocol.getServer();
961 if (server == null) {
962 if (protocol.getServerRemoveAppProvidedValues()) {
963 headers.removeHeader("server");
964 }
965 } else {
966
967 headers.setValue("Server").setString(server);
968 }
969
970
971 try {
972 outputBuffer.sendStatus();
973
974 int size = headers.size();
975 for (int i = 0; i < size; i++) {
976 outputBuffer.sendHeader(headers.getName(i), headers.getValue(i));
977 }
978 outputBuffer.endHeaders();
979 } catch (Throwable t) {
980 ExceptionUtils.handleThrowable(t);
981
982
983 outputBuffer.resetHeaderBuffer();
984 throw t;
985 }
986
987 outputBuffer.commit();
988 }
989
990 private static boolean isConnectionToken(MimeHeaders headers, String token) throws IOException {
991 MessageBytes connection = headers.getValue(Constants.CONNECTION);
992 if (connection == null) {
993 return false;
994 }
995
996 Set<String> tokens = new HashSet<>();
997 TokenList.parseTokenList(headers.values(Constants.CONNECTION), tokens);
998 return tokens.contains(token);
999 }
1000
1001
1002 private void prepareSendfile(OutputFilter[] outputFilters) {
1003 String fileName = (String) request.getAttribute(
1004 org.apache.coyote.Constants.SENDFILE_FILENAME_ATTR);
1005 if (fileName == null) {
1006 sendfileData = null;
1007 } else {
1008
1009 outputBuffer.addActiveFilter(outputFilters[Constants.VOID_FILTER]);
1010 contentDelimitation = true;
1011 long pos = ((Long) request.getAttribute(
1012 org.apache.coyote.Constants.SENDFILE_FILE_START_ATTR)).longValue();
1013 long end = ((Long) request.getAttribute(
1014 org.apache.coyote.Constants.SENDFILE_FILE_END_ATTR)).longValue();
1015 sendfileData = socketWrapper.createSendfileData(fileName, pos, end - pos);
1016 }
1017 }
1018
1019
1020
1025
1026
1027
1032 @Override
1033 protected void populatePort() {
1034
1035 request.action(ActionCode.REQ_LOCALPORT_ATTRIBUTE, request);
1036 request.setServerPort(request.getLocalPort());
1037 }
1038
1039
1040 @Override
1041 protected boolean flushBufferedWrite() throws IOException {
1042 if (outputBuffer.hasDataToWrite()) {
1043 if (outputBuffer.flushBuffer(false)) {
1044
1045
1046
1047
1048
1049
1050
1051 outputBuffer.registerWriteInterest();
1052 return true;
1053 }
1054 }
1055 return false;
1056 }
1057
1058
1059 @Override
1060 protected SocketState dispatchEndRequest() {
1061 if (!keepAlive || protocol.isPaused()) {
1062 return SocketState.CLOSED;
1063 } else {
1064 endRequest();
1065 inputBuffer.nextRequest();
1066 outputBuffer.nextRequest();
1067 if (socketWrapper.isReadPending()) {
1068 return SocketState.LONG;
1069 } else {
1070 return SocketState.OPEN;
1071 }
1072 }
1073 }
1074
1075
1076 @Override
1077 protected Log getLog() {
1078 return log;
1079 }
1080
1081
1082
1087 private void endRequest() {
1088 if (getErrorState().isError()) {
1089
1090
1091
1092 inputBuffer.setSwallowInput(false);
1093 } else {
1094
1095
1096
1097 checkExpectationAndResponseStatus();
1098 }
1099
1100
1101 if (getErrorState().isIoAllowed()) {
1102 try {
1103 inputBuffer.endRequest();
1104 } catch (IOException e) {
1105 setErrorState(ErrorState.CLOSE_CONNECTION_NOW, e);
1106 } catch (Throwable t) {
1107 ExceptionUtils.handleThrowable(t);
1108
1109
1110
1111 response.setStatus(500);
1112 setErrorState(ErrorState.CLOSE_NOW, t);
1113 log.error(sm.getString("http11processor.request.finish"), t);
1114 }
1115 }
1116 if (getErrorState().isIoAllowed()) {
1117 try {
1118 action(ActionCode.COMMIT, null);
1119 outputBuffer.end();
1120 } catch (IOException e) {
1121 setErrorState(ErrorState.CLOSE_CONNECTION_NOW, e);
1122 } catch (Throwable t) {
1123 ExceptionUtils.handleThrowable(t);
1124 setErrorState(ErrorState.CLOSE_NOW, t);
1125 log.error(sm.getString("http11processor.response.finish"), t);
1126 }
1127 }
1128 }
1129
1130
1131 @Override
1132 protected final void finishResponse() throws IOException {
1133 outputBuffer.end();
1134 }
1135
1136
1137 @Override
1138 protected final void ack() {
1139
1140
1141
1142 if (!response.isCommitted() && request.hasExpectation()) {
1143 inputBuffer.setSwallowInput(true);
1144 try {
1145 outputBuffer.sendAck();
1146 } catch (IOException e) {
1147 setErrorState(ErrorState.CLOSE_CONNECTION_NOW, e);
1148 }
1149 }
1150 }
1151
1152
1153 @Override
1154 protected final void flush() throws IOException {
1155 outputBuffer.flush();
1156 }
1157
1158
1159 @Override
1160 protected final int available(boolean doRead) {
1161 return inputBuffer.available(doRead);
1162 }
1163
1164
1165 @Override
1166 protected final void setRequestBody(ByteChunk body) {
1167 InputFilter savedBody = new SavedRequestInputFilter(body);
1168 Http11InputBuffer internalBuffer = (Http11InputBuffer) request.getInputBuffer();
1169 internalBuffer.addActiveFilter(savedBody);
1170 }
1171
1172
1173 @Override
1174 protected final void setSwallowResponse() {
1175 outputBuffer.responseFinished = true;
1176 }
1177
1178
1179 @Override
1180 protected final void disableSwallowRequest() {
1181 inputBuffer.setSwallowInput(false);
1182 }
1183
1184
1185 @Override
1186 protected final void sslReHandShake() throws IOException {
1187 if (sslSupport != null) {
1188
1189
1190 InputFilter[] inputFilters = inputBuffer.getFilters();
1191 ((BufferedInputFilter) inputFilters[Constants.BUFFERED_FILTER]).setLimit(
1192 protocol.getMaxSavePostSize());
1193 inputBuffer.addActiveFilter(inputFilters[Constants.BUFFERED_FILTER]);
1194
1195
1200 socketWrapper.doClientAuth(sslSupport);
1201 try {
1202
1206 Object sslO = sslSupport.getPeerCertificateChain();
1207 if (sslO != null) {
1208 request.setAttribute(SSLSupport.CERTIFICATE_KEY, sslO);
1209 }
1210 } catch (IOException ioe) {
1211 log.warn(sm.getString("http11processor.socket.ssl"), ioe);
1212 }
1213 }
1214 }
1215
1216
1217 @Override
1218 protected final boolean isRequestBodyFullyRead() {
1219 return inputBuffer.isFinished();
1220 }
1221
1222
1223 @Override
1224 protected final void registerReadInterest() {
1225 socketWrapper.registerReadInterest();
1226 }
1227
1228
1229 @Override
1230 protected final boolean isReadyForWrite() {
1231 return outputBuffer.isReady();
1232 }
1233
1234
1235 @Override
1236 public UpgradeToken getUpgradeToken() {
1237 return upgradeToken;
1238 }
1239
1240
1241 @Override
1242 protected final void doHttpUpgrade(UpgradeToken upgradeToken) {
1243 this.upgradeToken = upgradeToken;
1244
1245 outputBuffer.responseFinished = true;
1246 }
1247
1248
1249 @Override
1250 public ByteBuffer getLeftoverInput() {
1251 return inputBuffer.getLeftover();
1252 }
1253
1254
1255 @Override
1256 public boolean isUpgrade() {
1257 return upgradeToken != null;
1258 }
1259
1260
1261 @Override
1262 protected boolean isTrailerFieldsReady() {
1263 if (inputBuffer.isChunking()) {
1264 return inputBuffer.isFinished();
1265 } else {
1266 return true;
1267 }
1268 }
1269
1270
1271 @Override
1272 protected boolean isTrailerFieldsSupported() {
1273
1274 if (!http11) {
1275 return false;
1276 }
1277
1278
1279
1280 if (!response.isCommitted()) {
1281 return true;
1282 }
1283
1284
1285 return outputBuffer.isChunking();
1286 }
1287
1288
1289
1294 private SendfileState processSendfile(SocketWrapperBase<?> socketWrapper) {
1295 openSocket = keepAlive;
1296
1297 SendfileState result = SendfileState.DONE;
1298
1299 if (sendfileData != null && !getErrorState().isError()) {
1300 if (keepAlive) {
1301 if (available(false) == 0) {
1302 sendfileData.keepAliveState = SendfileKeepAliveState.OPEN;
1303 } else {
1304 sendfileData.keepAliveState = SendfileKeepAliveState.PIPELINED;
1305 }
1306 } else {
1307 sendfileData.keepAliveState = SendfileKeepAliveState.NONE;
1308 }
1309 result = socketWrapper.processSendfile(sendfileData);
1310 switch (result) {
1311 case ERROR:
1312
1313 if (log.isDebugEnabled()) {
1314 log.debug(sm.getString("http11processor.sendfile.error"));
1315 }
1316 setErrorState(ErrorState.CLOSE_CONNECTION_NOW, null);
1317
1318 default:
1319 sendfileData = null;
1320 }
1321 }
1322 return result;
1323 }
1324
1325
1326 @Override
1327 public final void recycle() {
1328 getAdapter().checkRecycled(request, response);
1329 super.recycle();
1330 inputBuffer.recycle();
1331 outputBuffer.recycle();
1332 upgradeToken = null;
1333 socketWrapper = null;
1334 sendfileData = null;
1335 sslSupport = null;
1336 }
1337
1338
1339 @Override
1340 public void pause() {
1341
1342 }
1343 }
1344