/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License.
*/ package org.apache.coyote.http11;
/** * Provides buffering for the HTTP headers (allowing responses to be reset before they have been committed) and the link * to the Socket for writing the headers (once committed) and the response body. Note that buffering of the response * body happens at a higher level.
*/ publicclass Http11OutputBuffer implements HttpOutputBuffer {
/** * Add an output filter to the filter library. Note that calling this method resets the currently active filters to * none. * * @param filter The filter to add
*/ publicvoid addFilter(OutputFilter filter) {
activeFilters = new OutputFilter[filterLibrary.length];
}
/** * Get filters. * * @return The current filter library containing all possible filters
*/ public OutputFilter[] getFilters() { return filterLibrary;
}
/** * Add an output filter to the active filters for the current response. * <p> * The filter does not have to be present in {@link #getFilters()}. * <p> * A filter can only be added to a response once. If the filter has already been added to this response then this * method will be a NO-OP. * * @param filter The filter to add
*/ publicvoid addActiveFilter(OutputFilter filter) {
if (lastActiveFilter == -1) {
filter.setBuffer(outputStreamOutputBuffer);
} else { for (int i = 0; i <= lastActiveFilter; i++) { if (activeFilters[i] == filter) { return;
}
}
filter.setBuffer(activeFilters[lastActiveFilter]);
}
if (!response.isCommitted()) { // Send the connector a request for commit. The connector should // then validate the headers, send them (using sendHeaders) and // set the filters accordingly.
response.action(ActionCode.COMMIT, null);
}
// --------------------------------------------------------- Public Methods
/** * Reset the header buffer if an error occurs during the writing of the headers so the error response can be * written.
*/ void resetHeaderBuffer() {
headerBuffer.position(0).limit(headerBuffer.capacity());
}
/** * Recycle the output buffer. This should be called when closing the connection.
*/ publicvoid recycle() {
nextRequest();
socketWrapper = null;
}
/** * End processing of current HTTP request. Note: All bytes of the current request should have been already consumed. * This method only resets all the pointers so that we are ready to parse the next HTTP request.
*/ publicvoid nextRequest() { // Recycle filters for (int i = 0; i <= lastActiveFilter; i++) {
activeFilters[i].recycle();
} // Recycle response object
response.recycle(); // Reset pointers
headerBuffer.position(0).limit(headerBuffer.capacity());
lastActiveFilter = -1;
ackSent = false;
responseFinished = false;
byteCount = 0;
}
publicvoid sendAck() throws IOException { // It possible that the protocol configuration is changed between the // request being received and the first read of the body. That could led // to multiple calls to this method so ensure the ACK is only sent once. if (!response.isCommitted() && !ackSent) {
ackSent = true;
socketWrapper.write(isBlocking(), Constants.ACK_BYTES, 0, Constants.ACK_BYTES.length); if (flushBuffer(true)) { thrownew IOException(sm.getString("iob.failedwrite.ack"));
}
}
}
/** * Send the response status line.
*/ publicvoid sendStatus() { // Write protocol name
write(Constants.HTTP_11_BYTES);
headerBuffer.put(Constants.SP);
// Write status code int status = response.getStatus(); switch (status) { case 200:
write(Constants._200_BYTES); break; case 400:
write(Constants._400_BYTES); break; case 404:
write(Constants._404_BYTES); break; default:
write(status);
}
headerBuffer.put(Constants.SP);
// The reason phrase is optional but the space before it is not. Skip // sending the reason phrase. Clients should ignore it (RFC 7230) and it // just wastes bytes.
/** * Send a header. * * @param name Header name * @param value Header value
*/ publicvoid sendHeader(MessageBytes name, MessageBytes value) {
write(name);
headerBuffer.put(Constants.COLON).put(Constants.SP);
write(value);
headerBuffer.put(Constants.CR).put(Constants.LF);
}
/** * End the header block.
*/ publicvoid endHeaders() {
headerBuffer.put(Constants.CR).put(Constants.LF);
}
/** * This method will write the contents of the specified message bytes buffer to the output stream, without * filtering. This method is meant to be used to write the response header. * * @param mb data to be written
*/ privatevoid write(MessageBytes mb) { if (mb.getType() != MessageBytes.T_BYTES) {
mb.toBytes();
ByteChunk bc = mb.getByteChunk(); // Need to filter out CTLs excluding TAB. ISO-8859-1 and UTF-8 // values will be OK. Strings using other encodings may be // corrupted. byte[] buffer = bc.getBuffer(); for (int i = bc.getOffset(); i < bc.getLength(); i++) { // byte values are signed i.e. -128 to 127 // The values are used unsigned. 0 to 31 are CTLs so they are // filtered (apart from TAB which is 9). 127 is a control (DEL). // The values 128 to 255 are all OK. Converting those to signed // gives -128 to -1. if ((buffer[i] > -1 && buffer[i] <= 31 && buffer[i] != 9) || buffer[i] == 127) {
buffer[i] = ' ';
}
}
}
write(mb.getByteChunk());
}
/** * This method will write the contents of the specified byte chunk to the output stream, without filtering. This * method is meant to be used to write the response header. * * @param bc data to be written
*/ privatevoid write(ByteChunk bc) { // Writing the byte chunk to the output buffer int length = bc.getLength();
checkLengthBeforeWrite(length);
headerBuffer.put(bc.getBytes(), bc.getStart(), length);
}
/** * This method will write the contents of the specified byte buffer to the output stream, without filtering. This * method is meant to be used to write the response header. * * @param b data to be written
*/ publicvoid write(byte[] b) {
checkLengthBeforeWrite(b.length);
// Writing the byte chunk to the output buffer
headerBuffer.put(b);
}
/** * This method will write the specified integer to the output stream. This method is meant to be used to write the * response header. * * @param value data to be written
*/ privatevoid write(int value) { // From the Tomcat 3.3 HTTP/1.0 connector
String s = Integer.toString(value); int len = s.length();
checkLengthBeforeWrite(len); for (int i = 0; i < len; i++) { char c = s.charAt(i);
headerBuffer.put((byte) c);
}
}
/** * Checks to see if there is enough space in the buffer to write the requested number of bytes.
*/ privatevoid checkLengthBeforeWrite(int length) { // "+ 4": BZ 57509. Reserve space for CR/LF/COLON/SP characters that // are put directly into the buffer following this write operation. if (headerBuffer.position() + length + 4 > headerBuffer.capacity()) { thrownew HeadersTooLargeException(sm.getString("iob.responseheadertoolarge.error"));
}
}
/** * Writes any remaining buffered data. * * @param block Should this method block until the buffer is empty * * @return <code>true</code> if data remains in the buffer (which can only happen in non-blocking mode) else * <code>false</code>. * * @throws IOException Error writing data
*/ protectedboolean flushBuffer(boolean block) throws IOException { return socketWrapper.flush(block);
}
/** * Is standard Servlet blocking IO being used for output? * * @return <code>true</code> if this is blocking IO
*/ protectedfinalboolean isBlocking() { return response.getWriteListener() == null;
}
protectedfinalboolean isReady() { boolean result = !hasDataToWrite(); if (!result) {
socketWrapper.registerWriteInterest();
} return result;
}
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.16Bemerkung:
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.