This commit is contained in:
2024-11-30 19:03:49 +08:00
commit 1e6763c160
3806 changed files with 737676 additions and 0 deletions

View File

@@ -0,0 +1,52 @@
/*
* 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;
import org.apache.tomcat.util.net.AbstractJsseEndpoint;
import org.apache.tomcat.util.net.openssl.OpenSSLImplementation;
public abstract class AbstractHttp11JsseProtocol<S>
extends AbstractHttp11Protocol<S> {
public AbstractHttp11JsseProtocol(AbstractJsseEndpoint<S> endpoint) {
super(endpoint);
}
@Override
protected AbstractJsseEndpoint<S> getEndpoint() {
// Over-ridden to add cast
return (AbstractJsseEndpoint<S>) super.getEndpoint();
}
protected String getSslImplementationShortName() {
if (OpenSSLImplementation.class.getName().equals(getSslImplementationName())) {
return "openssl";
}
return "jsse";
}
public String getSslImplementationName() { return getEndpoint().getSslImplementationName(); }
public void setSslImplementationName(String s) { getEndpoint().setSslImplementationName(s); }
public int getSniParseLimit() { return getEndpoint().getSniParseLimit(); }
public void setSniParseLimit(int sniParseLimit) {
getEndpoint().setSniParseLimit(sniParseLimit);
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,179 @@
/*
* 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;
import org.apache.tomcat.util.buf.ByteChunk;
/**
* Constants.
*
* @author Remy Maucherat
*/
public final class Constants {
public static final int DEFAULT_CONNECTION_TIMEOUT = 60000;
/**
* CRLF.
*/
public static final String CRLF = "\r\n";
/**
* CR.
*/
public static final byte CR = (byte) '\r';
/**
* LF.
*/
public static final byte LF = (byte) '\n';
/**
* SP.
*/
public static final byte SP = (byte) ' ';
/**
* HT.
*/
public static final byte HT = (byte) '\t';
/**
* COLON.
*/
public static final byte COLON = (byte) ':';
/**
* SEMI_COLON.
*/
public static final byte SEMI_COLON = (byte) ';';
/**
* 'A'.
*/
public static final byte A = (byte) 'A';
/**
* 'a'.
*/
public static final byte a = (byte) 'a';
/**
* 'Z'.
*/
public static final byte Z = (byte) 'Z';
/**
* '?'.
*/
public static final byte QUESTION = (byte) '?';
/**
* Lower case offset.
*/
public static final byte LC_OFFSET = A - a;
/* Various constant "strings" */
public static final String CONNECTION = "Connection";
public static final String CLOSE = "close";
/**
* @deprecated Unused. Will be removed in Tomcat 10.
*/
@Deprecated
public static final byte[] CLOSE_BYTES = ByteChunk.convertToBytes(CLOSE);
/**
* @deprecated Unused. Will be removed in Tomcat 10.
*/
@Deprecated
public static final String KEEPALIVE = "keep-alive";
public static final String KEEP_ALIVE_HEADER_VALUE_TOKEN = "keep-alive";
/**
* @deprecated Unused. Will be removed in Tomcat 10.
*/
@Deprecated
public static final byte[] KEEPALIVE_BYTES = ByteChunk.convertToBytes(KEEPALIVE);
public static final String CHUNKED = "chunked";
/**
* @deprecated This option will be removed in Tomcat 9. Reason phrase will
* not be sent.
*/
@Deprecated
public static final byte[] ACK_BYTES_REASON =
ByteChunk.convertToBytes("HTTP/1.1 100 Continue" + CRLF + CRLF);
public static final byte[] ACK_BYTES = ByteChunk.convertToBytes("HTTP/1.1 100 " + CRLF + CRLF);
public static final String TRANSFERENCODING = "Transfer-Encoding";
public static final String KEEP_ALIVE_HEADER_NAME = "Keep-Alive";
public static final byte[] _200_BYTES = ByteChunk.convertToBytes("200");
public static final byte[] _400_BYTES = ByteChunk.convertToBytes("400");
public static final byte[] _404_BYTES = ByteChunk.convertToBytes("404");
/**
* Identity filters (input and output).
*/
public static final int IDENTITY_FILTER = 0;
/**
* Chunked filters (input and output).
*/
public static final int CHUNKED_FILTER = 1;
/**
* Void filters (input and output).
*/
public static final int VOID_FILTER = 2;
/**
* GZIP filter (output).
*/
public static final int GZIP_FILTER = 3;
/**
* Buffered filter (input)
*/
public static final int BUFFERED_FILTER = 3;
/**
* HTTP/1.0.
*/
public static final String HTTP_10 = "HTTP/1.0";
/**
* HTTP/1.1.
*/
public static final String HTTP_11 = "HTTP/1.1";
public static final byte[] HTTP_11_BYTES = ByteChunk.convertToBytes(HTTP_11);
}

View File

@@ -0,0 +1,42 @@
/*
* 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;
/**
* Exception used to mark the specific error condition of the HTTP headers
* exceeding the maximum permitted size.
*/
public class HeadersTooLargeException extends IllegalStateException {
private static final long serialVersionUID = 1L;
public HeadersTooLargeException() {
super();
}
public HeadersTooLargeException(String message, Throwable cause) {
super(message, cause);
}
public HeadersTooLargeException(String s) {
super(s);
}
public HeadersTooLargeException(Throwable cause) {
super(cause);
}
}

View File

@@ -0,0 +1,71 @@
/*
* 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;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
import org.apache.tomcat.util.net.AprEndpoint;
/**
* Abstract the protocol implementation, including threading, etc.
* Processor is single threaded and specific to stream-based protocols,
* will not fit Jk protocols like JNI.
*
* @author Remy Maucherat
* @author Costin Manolache
*/
public class Http11AprProtocol extends AbstractHttp11Protocol<Long> {
private static final Log log = LogFactory.getLog(Http11AprProtocol.class);
public Http11AprProtocol() {
super(new AprEndpoint());
}
@Override
protected Log getLog() { return log; }
@Override
public boolean isAprRequired() {
// Override since this protocol implementation requires the APR/native
// library
return true;
}
public int getPollTime() { return ((AprEndpoint)getEndpoint()).getPollTime(); }
public void setPollTime(int pollTime) { ((AprEndpoint)getEndpoint()).setPollTime(pollTime); }
public int getSendfileSize() { return ((AprEndpoint)getEndpoint()).getSendfileSize(); }
public void setSendfileSize(int sendfileSize) { ((AprEndpoint)getEndpoint()).setSendfileSize(sendfileSize); }
public boolean getDeferAccept() { return ((AprEndpoint)getEndpoint()).getDeferAccept(); }
public void setDeferAccept(boolean deferAccept) { ((AprEndpoint)getEndpoint()).setDeferAccept(deferAccept); }
// ----------------------------------------------------- JMX related methods
@Override
protected String getNamePrefix() {
if (isSSLEnabled()) {
return ("https-openssl-apr");
} else {
return ("http-apr");
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,52 @@
/*
* 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;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
import org.apache.tomcat.util.net.Nio2Channel;
import org.apache.tomcat.util.net.Nio2Endpoint;
/**
* HTTP/1.1 protocol implementation using NIO2.
*/
public class Http11Nio2Protocol extends AbstractHttp11JsseProtocol<Nio2Channel> {
private static final Log log = LogFactory.getLog(Http11Nio2Protocol.class);
public Http11Nio2Protocol() {
super(new Nio2Endpoint());
}
@Override
protected Log getLog() { return log; }
// ----------------------------------------------------- JMX related methods
@Override
protected String getNamePrefix() {
if (isSSLEnabled()) {
return ("https-" + getSslImplementationShortName()+ "-nio2");
} else {
return ("http-nio2");
}
}
}

View File

@@ -0,0 +1,84 @@
/*
* 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;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
import org.apache.tomcat.util.net.NioChannel;
import org.apache.tomcat.util.net.NioEndpoint;
/**
* Abstract the protocol implementation, including threading, etc.
* Processor is single threaded and specific to stream-based protocols,
* will not fit Jk protocols like JNI.
*
* @author Remy Maucherat
* @author Costin Manolache
*/
public class Http11NioProtocol extends AbstractHttp11JsseProtocol<NioChannel> {
private static final Log log = LogFactory.getLog(Http11NioProtocol.class);
public Http11NioProtocol() {
super(new NioEndpoint());
}
@Override
protected Log getLog() { return log; }
// -------------------- Pool setup --------------------
public void setPollerThreadCount(int count) {
((NioEndpoint)getEndpoint()).setPollerThreadCount(count);
}
public int getPollerThreadCount() {
return ((NioEndpoint)getEndpoint()).getPollerThreadCount();
}
public void setSelectorTimeout(long timeout) {
((NioEndpoint)getEndpoint()).setSelectorTimeout(timeout);
}
public long getSelectorTimeout() {
return ((NioEndpoint)getEndpoint()).getSelectorTimeout();
}
public void setPollerThreadPriority(int threadPriority) {
((NioEndpoint)getEndpoint()).setPollerThreadPriority(threadPriority);
}
public int getPollerThreadPriority() {
return ((NioEndpoint)getEndpoint()).getPollerThreadPriority();
}
// ----------------------------------------------------- JMX related methods
@Override
protected String getNamePrefix() {
if (isSSLEnabled()) {
return ("https-" + getSslImplementationShortName()+ "-nio");
} else {
return ("http-nio");
}
}
}

View File

@@ -0,0 +1,649 @@
/*
* 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;
import java.io.IOException;
import java.nio.ByteBuffer;
import org.apache.coyote.ActionCode;
import org.apache.coyote.Response;
import org.apache.tomcat.util.buf.ByteChunk;
import org.apache.tomcat.util.buf.MessageBytes;
import org.apache.tomcat.util.http.HttpMessages;
import org.apache.tomcat.util.net.SocketWrapperBase;
import org.apache.tomcat.util.res.StringManager;
/**
* 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.
*/
public class Http11OutputBuffer implements HttpOutputBuffer {
// -------------------------------------------------------------- Variables
/**
* The string manager for this package.
*/
protected static final StringManager sm = StringManager.getManager(Http11OutputBuffer.class);
// ----------------------------------------------------- Instance Variables
/**
* Associated Coyote response.
*/
protected Response response;
/**
* Finished flag.
*/
protected boolean responseFinished;
/**
* The buffer used for header composition.
*/
protected final ByteBuffer headerBuffer;
/**
* Filter library for processing the response body.
*/
protected OutputFilter[] filterLibrary;
/**
* Active filters for the current request.
*/
protected OutputFilter[] activeFilters;
/**
* Index of the last active filter.
*/
protected int lastActiveFilter;
/**
* Underlying output buffer.
*/
protected HttpOutputBuffer outputStreamOutputBuffer;
/**
* Wrapper for socket where data will be written to.
*/
protected SocketWrapperBase<?> socketWrapper;
/**
* Bytes written to client for the current request
*/
protected long byteCount = 0;
@Deprecated
private boolean sendReasonPhrase = false;
protected Http11OutputBuffer(Response response, int headerBufferSize, boolean sendReasonPhrase) {
this.response = response;
this.sendReasonPhrase = sendReasonPhrase;
headerBuffer = ByteBuffer.allocate(headerBufferSize);
filterLibrary = new OutputFilter[0];
activeFilters = new OutputFilter[0];
lastActiveFilter = -1;
responseFinished = false;
outputStreamOutputBuffer = new SocketOutputBuffer();
if (sendReasonPhrase) {
// Cause loading of HttpMessages
HttpMessages.getInstance(response.getLocale()).getMessage(200);
}
}
// ------------------------------------------------------------- Properties
/**
* 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
*/
public void addFilter(OutputFilter filter) {
OutputFilter[] newFilterLibrary = new OutputFilter[filterLibrary.length + 1];
for (int i = 0; i < filterLibrary.length; i++) {
newFilterLibrary[i] = filterLibrary[i];
}
newFilterLibrary[filterLibrary.length] = filter;
filterLibrary = newFilterLibrary;
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
*/
public void 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]);
}
activeFilters[++lastActiveFilter] = filter;
filter.setResponse(response);
}
// --------------------------------------------------- OutputBuffer Methods
/**
* @deprecated Unused. Will be removed in Tomcat 9. Use
* {@link #doWrite(ByteBuffer)}
*/
@Deprecated
@Override
public int doWrite(ByteChunk chunk) throws IOException {
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);
}
if (lastActiveFilter == -1) {
return outputStreamOutputBuffer.doWrite(chunk);
} else {
return activeFilters[lastActiveFilter].doWrite(chunk);
}
}
@Override
public int doWrite(ByteBuffer chunk) throws IOException {
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);
}
if (lastActiveFilter == -1) {
return outputStreamOutputBuffer.doWrite(chunk);
} else {
return activeFilters[lastActiveFilter].doWrite(chunk);
}
}
@Override
public long getBytesWritten() {
if (lastActiveFilter == -1) {
return outputStreamOutputBuffer.getBytesWritten();
} else {
return activeFilters[lastActiveFilter].getBytesWritten();
}
}
// ----------------------------------------------- HttpOutputBuffer Methods
/**
* Flush the response.
*
* @throws IOException an underlying I/O error occurred
*/
@Override
public void flush() throws IOException {
if (lastActiveFilter == -1) {
outputStreamOutputBuffer.flush();
} else {
activeFilters[lastActiveFilter].flush();
}
}
@Override
public void end() throws IOException {
if (responseFinished) {
return;
}
if (lastActiveFilter == -1) {
outputStreamOutputBuffer.end();
} else {
activeFilters[lastActiveFilter].end();
}
responseFinished = true;
}
// --------------------------------------------------------- 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.
*/
public void 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.
*/
public void 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;
responseFinished = false;
byteCount = 0;
}
public void init(SocketWrapperBase<?> socketWrapper) {
this.socketWrapper = socketWrapper;
}
@SuppressWarnings("deprecation")
public void sendAck() throws IOException {
if (!response.isCommitted()) {
if (sendReasonPhrase) {
socketWrapper.write(isBlocking(), Constants.ACK_BYTES_REASON, 0, Constants.ACK_BYTES_REASON.length);
} else {
socketWrapper.write(isBlocking(), Constants.ACK_BYTES, 0, Constants.ACK_BYTES.length);
}
if (flushBuffer(true)) {
throw new IOException(sm.getString("iob.failedwrite.ack"));
}
}
}
/**
* Commit the response.
*
* @throws IOException an underlying I/O error occurred
*/
protected void commit() throws IOException {
response.setCommitted(true);
if (headerBuffer.position() > 0) {
// Sending the response header buffer
headerBuffer.flip();
try {
socketWrapper.write(isBlocking(), headerBuffer);
} finally {
headerBuffer.position(0).limit(headerBuffer.capacity());
}
}
}
/**
* Send the response status line.
*/
@SuppressWarnings("deprecation")
public void 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);
if (sendReasonPhrase) {
// Write message
String message = null;
if (org.apache.coyote.Constants.USE_CUSTOM_STATUS_MSG_IN_HEADER &&
HttpMessages.isSafeInHttpHeader(response.getMessage())) {
message = response.getMessage();
}
if (message == null) {
write(HttpMessages.getInstance(
response.getLocale()).getMessage(status));
} else {
write(message);
}
} else {
// 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.
}
headerBuffer.put(Constants.CR).put(Constants.LF);
}
/**
* Send a header.
*
* @param name Header name
* @param value Header value
*/
public void 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.
*/
public void 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
*/
private void 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
*/
private void 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
*/
public void write(byte[] b) {
checkLengthBeforeWrite(b.length);
// Writing the byte chunk to the output buffer
headerBuffer.put(b);
}
/**
* This method will write the contents of the specified String to the
* output stream, without filtering. This method is meant to be used to
* write the response header.
*
* @param s data to be written
*/
private void write(String s) {
if (s == null) {
return;
}
// From the Tomcat 3.3 HTTP/1.0 connector
int len = s.length();
checkLengthBeforeWrite(len);
for (int i = 0; i < len; i++) {
char c = s.charAt (i);
// Note: This is clearly incorrect for many strings,
// but is the only consistent approach within the current
// servlet framework. It must suffice until servlet output
// streams properly encode their output.
if (((c <= 31) && (c != 9)) || c == 127 || c > 255) {
c = ' ';
}
headerBuffer.put((byte) c);
}
}
/**
* 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
*/
private void 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.
*/
private void 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()) {
throw new HeadersTooLargeException(
sm.getString("iob.responseheadertoolarge.error"));
}
}
//------------------------------------------------------ Non-blocking writes
/**
* 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
*/
protected boolean 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
*/
protected final boolean isBlocking() {
return response.getWriteListener() == null;
}
protected final boolean isReady() {
boolean result = !hasDataToWrite();
if (!result) {
socketWrapper.registerWriteInterest();
}
return result;
}
public boolean hasDataToWrite() {
return socketWrapper.hasDataToWrite();
}
public void registerWriteInterest() {
socketWrapper.registerWriteInterest();
}
// ------------------------------------------ SocketOutputBuffer Inner Class
/**
* This class is an output buffer which will write data to a socket.
*/
protected class SocketOutputBuffer implements HttpOutputBuffer {
/**
* Write chunk.
*
* @deprecated Unused. Will be removed in Tomcat 9. Use
* {@link #doWrite(ByteBuffer)}
*/
@Deprecated
@Override
public int doWrite(ByteChunk chunk) throws IOException {
int len = chunk.getLength();
int start = chunk.getStart();
byte[] b = chunk.getBuffer();
socketWrapper.write(isBlocking(), b, start, len);
byteCount += len;
return len;
}
/**
* Write chunk.
*/
@Override
public int doWrite(ByteBuffer chunk) throws IOException {
try {
int len = chunk.remaining();
socketWrapper.write(isBlocking(), chunk);
len -= chunk.remaining();
byteCount += len;
return len;
} catch (IOException ioe) {
response.action(ActionCode.CLOSE_NOW, ioe);
// Re-throw
throw ioe;
}
}
@Override
public long getBytesWritten() {
return byteCount;
}
@Override
public void end() throws IOException {
socketWrapper.flush(true);
}
@Override
public void flush() throws IOException {
socketWrapper.flush(isBlocking());
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,37 @@
/*
* 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;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
import org.apache.tomcat.util.res.StringManager;
/**
* @deprecated This class will be removed in Tomcat 9.
*/
@Deprecated
public class Http11Protocol extends Http11NioProtocol {
private static final Log log = LogFactory.getLog(Http11Protocol.class);
private static final StringManager sm = StringManager.getManager(Http11Protocol.class);
public Http11Protocol() {
super();
log.warn(sm.getString("http11protocol.noBio"));
}
}

View File

@@ -0,0 +1,40 @@
/*
* 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;
import java.io.IOException;
import org.apache.coyote.OutputBuffer;
public interface HttpOutputBuffer extends OutputBuffer {
/**
* Finish writing the current response. It is acceptable to write extra
* bytes using {@link #doWrite(java.nio.ByteBuffer)} during the execution of
* this method.
*
* @throws IOException If an I/O error occurs while writing to the client
*/
public void end() throws IOException;
/**
* Flushes any unwritten data to the client.
*
* @throws IOException If an I/O error occurs while flushing
*/
public void flush() throws IOException;
}

View File

@@ -0,0 +1,93 @@
/*
* 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;
import java.io.IOException;
import org.apache.coyote.InputBuffer;
import org.apache.coyote.Request;
import org.apache.tomcat.util.buf.ByteChunk;
/**
* Input filter interface.
*
* @author Remy Maucherat
*/
public interface InputFilter extends InputBuffer {
/**
* Some filters need additional parameters from the request.
*
* @param request The request to be associated with this filter
*/
public void setRequest(Request request);
/**
* Make the filter ready to process the next request.
*/
public void recycle();
/**
* Get the name of the encoding handled by this filter.
*
* @return The encoding name as a byte chunk to facilitate comparison with
* the value read from the HTTP headers which will also be a
* ByteChunk
*/
public ByteChunk getEncodingName();
/**
* Set the next buffer in the filter pipeline.
*
* @param buffer The next buffer
*/
public void setBuffer(InputBuffer buffer);
/**
* End the current request.
*
* @return 0 is the expected return value. A positive value indicates that
* too many bytes were read. This method is allowed to use buffer.doRead
* to consume extra bytes. The result of this method can't be negative (if
* an error happens, an IOException should be thrown instead).
*
* @throws IOException If an error happens
*/
public long end() throws IOException;
/**
* Amount of bytes still available in a buffer.
*
* @return The number of bytes in the buffer
*/
public int available();
/**
* Has the request body been read fully?
*
* @return {@code true} if the request body has been fully read, otherwise
* {@code false}
*/
public boolean isFinished();
}

View File

@@ -0,0 +1,55 @@
# 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.
abstractHttp11Protocol.alpnConfigured=The [{0}] connector has been configured to support negotiation to [{1}] via ALPN
abstractHttp11Protocol.alpnWithNoAlpn=The upgrade handler [{0}] for [{1}] only supports upgrade via ALPN but has been configured for the [{2}] connector that does not support ALPN.
abstractHttp11Protocol.httpUpgradeConfigured=The [{0}] connector has been configured to support HTTP upgrade to [{1}]
http11processor.fallToDebug=\n\
\ Note: further occurrences of HTTP request parsing errors will be logged at DEBUG level.
http11processor.header.parse=Error parsing HTTP request header
http11processor.request.finish=Error finishing request
http11processor.request.inconsistentHosts=The host specified in the request line is not consistent with the host header
http11processor.request.invalidScheme=The HTTP request contained an absolute URI with an invalid scheme
http11processor.request.invalidTransferEncoding=The HTTP request contained an invalid Transfer-Encoding header
http11processor.request.invalidUri=The HTTP request contained an invalid URI
http11processor.request.invalidUserInfo=The HTTP request contained an absolute URI with an invalid userinfo
http11processor.request.multipleContentLength=The request contained multiple content-length headers
http11processor.request.multipleHosts=The request contained multiple host headers
http11processor.request.noHostHeader=The HTTP/1.1 request did not provide a host header
http11processor.request.nonNumericContentLength=The request contained a content-length header with a non-numeric value
http11processor.request.prepare=Error preparing request
http11processor.request.process=Error processing request
http11processor.response.finish=Error finishing response
http11processor.sendfile.error=Error sending data using sendfile. May be caused by invalid request attributes for start/end points
http11processor.socket.info=Exception getting socket information
http11protocol.noBio=The HTTP BIO connector has been removed in Tomcat 8.5.x onwards. The HTTP BIO connector configuration has been automatically switched to use the HTTP NIO connector instead.
iib.available.readFail=A non-blocking read failed while attempting to determine if data was available
iib.eof.error=Unexpected EOF read on the socket
iib.failedread.apr=Read failed with APR/native error code [{0}]
iib.filter.npe=You may not add a null filter
iib.invalidHttpProtocol=Invalid character found in the HTTP protocol
iib.invalidRequestTarget=Invalid character found in the request target. The valid characters are defined in RFC 7230 and RFC 3986
iib.invalidheader=The HTTP header line [{0}] does not conform to RFC 7230 and has been ignored.
iib.invalidmethod=Invalid character found in method name. HTTP method names must be tokens
iib.parseheaders.ise.error=Unexpected state: headers already parsed. Buffer not recycled?
iib.readtimeout=Timeout attempting to read data from the socket
iib.requestheadertoolarge.error=Request header is too large
iob.failedwrite=Failed write
iob.failedwrite.ack=Failed to send HTTP 100 continue response
iob.responseheadertoolarge.error=An attempt was made to write more data to the response headers than there was room available in the buffer. Increase maxHttpHeaderSize on the connector or write less data into the response headers.

View File

@@ -0,0 +1,22 @@
# 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.
http11processor.request.prepare=Fehler beim vorbereiten der Anfrage
http11processor.request.process=Fehler bei der Verarbeitung der Anfrage
http11processor.socket.info=Ausnahme beim Lesen der Informationen zum Socket
iib.invalidmethod=Ungültiges Zeichen in Methoden Namen gefunden. HTTP Methoden Namen müssen Token nach RFC-7230 sein
iob.failedwrite=Fehlgeschlagener Schreibvorgang

View File

@@ -0,0 +1,29 @@
# 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.
http11processor.header.parse=Error analizando cabecera de requerimiento HTTP
http11processor.request.finish=Error acabando requerimiento
http11processor.request.prepare=Error preparando solicitud
http11processor.request.process=Error procesando requerimiento
http11processor.response.finish=Error acabando respuesta
http11processor.socket.info=Excepción obteniendo información de conector
iib.eof.error=Inesperado Fin De Archivo (EOF) leído en el enchufe (socket)
iib.invalidmethod=Se encontró un carácter inválido en el nombre del método. Los nombres de métodos HTTP deben ser tokens
iib.parseheaders.ise.error=Estado inesperado: las cabeceras ya fueron parseadas. No se ha reciclado el buffer??
iib.requestheadertoolarge.error=La cabecera del requerimiento es demasido grande
iob.failedwrite=Fallo de escritura
iob.responseheadertoolarge.error=Un intento para escribir más datos en las cabeceras de respuesta escribir fue hecho, sin embargo no hay más espacio disponible en el bufer. Aumente el parámetro maxHttpHeaderSize en el conector o escribe menos datos en las respuestas de las cabeceras.\n

View File

@@ -0,0 +1,51 @@
# 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.
abstractHttp11Protocol.alpnConfigured=Le connecteur [{0}] a été configuré pour supporter la négociation de [{1}] avec ALPN
abstractHttp11Protocol.alpnWithNoAlpn=Le gestionnaire de mise à niveau [{0}] pour [{1}] ne supporte qu''une mise à niveau via ALPN mais il a été configuré pour le connecteur [{2}] qui ne supporte pas ALPN
abstractHttp11Protocol.httpUpgradeConfigured=Le connecteur [{0}] a été configuré pour supporter la mise à niveau de HTTP vers [{1}]
http11processor.fallToDebug=\ Note: toutes les occurrences suivantes d'erreurs d'analyse des requêtes HTTP seront enregistrées au niveau DEBUG
http11processor.header.parse=Erreur lors de l'analyse d'un en-tête de requête HTTP
http11processor.request.finish=Erreur en terminant la requête
http11processor.request.inconsistentHosts=L'hôte spécifié dans la ligne de requête ne correspond pas à celui de l'en-tête hôte
http11processor.request.invalidScheme=La requête HTTP contenait une URi absolue avec un schéma invalide
http11processor.request.invalidUri==La requête HTTP contenait une URI invalide
http11processor.request.invalidUserInfo=La requête HTTP contenait un URI absolu avec un composant "userinfo" invalide
http11processor.request.multipleContentLength=La requête contenait plusieurs en-têtes content-length
http11processor.request.multipleHosts=La requête contenait plusieurs en-têtes hôtes
http11processor.request.noHostHeader=La requ6ete HTTP/1.1 ne contient pas d'en-tête host
http11processor.request.nonNumericContentLength=La requête contenait un en-tête content-length avec une valeur non numérique
http11processor.request.prepare=Echec de préparation de la requête
http11processor.request.process=Erreur de traitement de la requête
http11processor.response.finish=Erreur en finissant la réponse
http11processor.sendfile.error=Erreur d'envoi des données avec sendfile, cela peut être causé par des attributs de démarrage ou de fin incorrects dans la requête
http11processor.socket.info=Exception pendant la requête d'information sur le socket.
iib.available.readFail=Une lecture non-bloquante a échoué lors de la détermination préalable de données disponibles
iib.eof.error=Fin de flux (EOF) inattendue à la lecture sur la socket
iib.failedread.apr=Echec de lecteur avec le code d''erreur APR [{0}]
iib.filter.npe=Impossible d'ajouter un filtre null
iib.invalidHttpProtocol=Un caractère invalide a été trouvé dans le protocole HTTP
iib.invalidRequestTarget=Un caractère invalide a été trouvé dans la cible de la requête, les caractères valides sont définis dans RFC 7230 et RFC 3986
iib.invalidheader=La ligne d''en-être HTTP [{0}] n''est pas conforme à la RFC 7230 et a été ignorée
iib.invalidmethod=Caractère invalide trouvé dans le nom de méthode. Les noms HTTP doivent être des "token".
iib.parseheaders.ise.error=Etat inattendu, les en-êtres ont déjà été traités, il est possible que le buffer n'ait pas été recyclé
iib.readtimeout=Délai d'attente dépassé en lisant des données du socket
iib.requestheadertoolarge.error=L'entête de requête est trop important
iob.failedwrite=Echec d'écriture
iob.failedwrite.ack=Echec d'envoi de la réponse HTTP 100 Continue
iob.responseheadertoolarge.error=Essai d'écriture de plus de données dans les en-t^tes de réponse, qu'il n'y a de place disponible dans le tampon. Augmentez maxHttpHeaderSize pour le connecteur, ou écrivez moins de données dans les en-têtes de réponse.

View File

@@ -0,0 +1,49 @@
# 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.
abstractHttp11Protocol.alpnConfigured=[{0}]コネクタは、ALPN経由で[{1}]へのネゴシエーションをサポートするように構成されています
abstractHttp11Protocol.alpnWithNoAlpn=[{1}]のアップグレードハンドラ[{0}]は、ALPNによるアップグレードのみをサポートしていますが、ALPNをサポートしていない[{2}]コネクタ用に構成されています。
abstractHttp11Protocol.httpUpgradeConfigured=コネクタ[{0}]は、[{1}]へのHTTPアップグレードをサポートするように構成されています。
http11processor.fallToDebug=HTTPリクエスト構文解析エラーがさらに発生すると、DEBUGレベルでログに記録されます。
http11processor.header.parse=HTTP リクエストヘッダーを解釈できませんでした。
http11processor.request.finish=リクエスト終了処理エラー
http11processor.request.inconsistentHosts=リクエストラインに指定されたホストが Host ヘッダーの値と矛盾しています。
http11processor.request.invalidScheme=HTTP リクエストに不正なスキーマを指定した完全 URI が含まれています。
http11processor.request.invalidUri== HTTPリクエストに無効なURIが含まれています
http11processor.request.invalidUserInfo=HTTP リクエストに不正な userinfo を含む絶対 URI が指定されました。
http11processor.request.multipleHosts=リクエストには複数のホストヘッダーが含まれていました。
http11processor.request.noHostHeader=HTTP / 1.1リクエストでhostヘッダーが提供されませんでした。
http11processor.request.prepare=リクエストの準備に失敗しました。
http11processor.request.process=リクエスト処理中にエラーが発生しました
http11processor.response.finish=レスポンス終了処理のエラー
http11processor.sendfile.error=sendfileを使ってデータを送信中にエラーが発生しました 開始点または終了点の無効なリクエスト属性によって引き起こされる可能性があります。
http11processor.socket.info=ソケット情報を取得する際の例外
iib.available.readFail=利用できるデータがあるか確かめている途中でノンブロッキング読み込みが失敗しました。
iib.eof.error=ソケットから予期しないEOFを読み込みました
iib.failedread.apr=APR/nativeエラーコード[{0}]で読み取りが失敗しました。
iib.filter.npe=Nullフィルタを追加することはできません。
iib.invalidHttpProtocol=HTTPプロトコルで無効な文字が見つかりました。
iib.invalidRequestTarget=リクエストの宛先に不正な文字が含まれています。利用可能な文字は RFC 7230 および RFC 3986 に定義されています。
iib.invalidheader=HTTP ヘッダー行 [{0}]は RFC 7230 に適合しないため無視します。
iib.invalidmethod=HTTP メソッド名に不正な文字が含まれています。HTTP メソッド名は決められたトークンでなければなりません。
iib.parseheaders.ise.error=予期しない状態:ヘッダがすでに解析されています。 バッファはリサイクルされていませんか?
iib.readtimeout=ソケットからデータを読み取ろうとしている際のタイムアウト
iib.requestheadertoolarge.error=リクエストヘッダが長すぎます
iob.failedwrite=書き込みが失敗しました。
iob.failedwrite.ack=HTTP 100 continue レスポンスの送信に失敗しました
iob.responseheadertoolarge.error=レスポンスヘッダーにバッファー領域より大きなデータの書き込みが発生しました。データを小さくするか Connector の maxHttpHeaderSize を大きくしてください。

View File

@@ -0,0 +1,52 @@
# 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.
abstractHttp11Protocol.alpnConfigured=[{0}] connector는 ALPN을 통해 [{1}](으)로 negotiation을 지원하도록 설정되었습니다.
abstractHttp11Protocol.alpnWithNoAlpn=[{1}]을(를) 위한 업그레이드 핸들러 [{0}]은(는) 오직 ALPN을 통한 업그레이드만 지원합니다만, 해당 업그레이드 핸들러가 ALPN을 지원하지 않는 [{2}] Connector를 위해 설정되어 있습니다.
abstractHttp11Protocol.httpUpgradeConfigured=[{0}] connector가, [{1}](으)로 HTTP 업그레이드를 지원하도록 설정되어 있습니다.
http11processor.fallToDebug=\n\
비고: HTTP 요청 파싱 오류들이 더 발생하는 경우 DEBUG 레벨 로그로 기록될 것입니다.
http11processor.header.parse=HTTP 요청 헤더를 파싱하는 중 오류 발생
http11processor.request.finish=요청을 완료하는 중 오류 발생
http11processor.request.inconsistentHosts=요청 행(request line)에 지정된 호스트가, 호스트 헤더와 일관되지 않습니다.
http11processor.request.invalidScheme=HTTP 요청이 유효하지 않은 스킴을 가진 절대 URI를 포함했습니다.
http11processor.request.invalidUri==HTTP 요청이 유효하지 않은 URI를 포함했습니다.
http11processor.request.invalidUserInfo=HTTP 요청이, 유효하지 않은 userinfo를 가진 절대 URI를 포함했습니다.
http11processor.request.multipleContentLength=해당 요청이 복수 개의 Content-Length 헤더들을 포함했습니다.
http11processor.request.multipleHosts=요청이 여러 개의 호스트 헤더들을 포함했습니다.
http11processor.request.noHostHeader=HTTP/1.1 요청이 호스트 헤더를 제공하지 않았습니다.
http11processor.request.nonNumericContentLength=해당 요청이 숫자가 아닌 Content-Length 헤더 값을 포함했습니다.
http11processor.request.prepare=요청을 준비하는 중 오류 발생
http11processor.request.process=요청 처리 중 오류 발생
http11processor.response.finish=응답을 완료하는 중 오류 발생
http11processor.sendfile.error=sendfile을 사용하여 데이터를 보내는 중 오류 발생. 시작 지점과 종료 지점을 위한 요청 속성들이 유효하지 않아 발생했을 수 있습니다.
http11processor.socket.info=소켓에 대한 정보를 얻는 중 예외 발생
iib.available.readFail=데이터가 가용한지 결정하려 시도하는 동안, non-blocking 읽기가 실패했습니다.
iib.eof.error=소켓에서 예기치 않은 EOF를 읽었습니다.
iib.failedread.apr=APR/native 오류 코드 [{0}]와(과) 함께, 읽기가 실패했습니다.
iib.filter.npe=널인 필터를 추가할 수 없습니다.
iib.invalidHttpProtocol=HTTP 프로토콜에서 유효하지 않은 문자가 발견되었습니다.
iib.invalidRequestTarget=요청 타겟에서 유효하지 않은 문자가 발견되었습니다. 유효한 문자들은 RFC 7230과 RFC 3986에 정의되어 있습니다.
iib.invalidheader=HTTP 헤더 행 [{0}]이(가) RFC 7230을 준수하지 않아, 무시되었습니다.
iib.invalidmethod=메소드 이름에 유효하지 않은 문자가 발견되었습니다. HTTP 메소드 이름은 유효한 토큰이어야 합니다.
iib.parseheaders.ise.error=예기치 않은 상태: 헤더들이 이미 파싱되었습니다. 버퍼가 참조 해제되지 않았었나요?
iib.readtimeout=소켓으로부터 데이터를 읽으려 시도하는 중 제한 시간 초과
iib.requestheadertoolarge.error=요청 헤더가 너무 큽니다.
iob.failedwrite=쓰기 실패
iob.failedwrite.ack=HTTP 100 continue 응답을 보내지 못했습니다.
iob.responseheadertoolarge.error=응답 헤더들에 가용한 버퍼 공간을 초과하는 데이터를 쓰려는 시도가 발생했습니다. 해당 Connector의 maxHttpHeaderSize를 증가시키거나, 응답 헤더들에 보다 적은 데이터를 쓰도록 하십시오.

View File

@@ -0,0 +1,16 @@
# 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.
http11processor.request.process=Ошибка при обработке запроса

View File

@@ -0,0 +1,39 @@
# 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.
abstractHttp11Protocol.alpnConfigured=[{0}]连接器已配置为支持通过ALPN与[{1}]协商。
http11processor.header.parse=解析 HTTP 请求 header 错误
http11processor.request.inconsistentHosts=请求行中指定的主机与主机头不一致。
http11processor.request.invalidScheme=HTTP请求包含具有无效方案的绝对URL
http11processor.request.invalidUserInfo=HTTP 请求包含带有无效 userinfo 的绝对 URI
http11processor.request.multipleContentLength=请求包含了多个content-length请求头参数
http11processor.request.noHostHeader=http/1.1请求没有提供主机头
http11processor.request.prepare=准备请求时出错
http11processor.request.process=错误的处理请求
http11processor.response.finish=错误完成相应
http11processor.socket.info=获取socket信息异常
iib.available.readFail=尝试确定数据是否可用时,非阻塞读取失败
iib.eof.error=套接字读取到意外的EOF
iib.filter.npe=你不能添加空过滤器(null)
iib.invalidheader=HTTP header行 [{0}] 不符合RFC 7230并且已被忽略。
iib.invalidmethod=在方法名称中发现无效的字符串, HTTP 方法名必须是有效的符号.
iib.parseheaders.ise.error=意外状态:已解析标头。 缓冲池不回收?
iib.readtimeout=从套接字读取数据超时
iob.failedwrite=写入.失败
iob.failedwrite.ack=无法发送HTTP 100继续响应
iob.responseheadertoolarge.error=尝试将更多数据写入响应标头,而不是缓冲区中有可用空间。 增加连接器上的maxHttpHeaderSize或将更少的数据写入响应头。

View File

@@ -0,0 +1,50 @@
/*
* 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;
import org.apache.coyote.Response;
/**
* Output filter.
*
* @author Remy Maucherat
*/
public interface OutputFilter extends HttpOutputBuffer {
/**
* Some filters need additional parameters from the response. All the
* necessary reading can occur in that method, as this method is called
* after the response header processing is complete.
*
* @param response The response to associate with this OutputFilter
*/
public void setResponse(Response response);
/**
* Make the filter ready to process the next request.
*/
public void recycle();
/**
* Set the next buffer in the filter pipeline.
*
* @param buffer The next buffer instance
*/
public void setBuffer(HttpOutputBuffer buffer);
}

View File

@@ -0,0 +1,188 @@
/*
* 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.filters;
import java.io.IOException;
import java.nio.BufferOverflowException;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import org.apache.coyote.InputBuffer;
import org.apache.coyote.Request;
import org.apache.coyote.http11.InputFilter;
import org.apache.tomcat.util.buf.ByteChunk;
import org.apache.tomcat.util.net.ApplicationBufferHandler;
/**
* Input filter responsible for reading and buffering the request body, so that
* it does not interfere with client SSL handshake messages.
*/
public class BufferedInputFilter implements InputFilter, ApplicationBufferHandler {
// -------------------------------------------------------------- Constants
private static final String ENCODING_NAME = "buffered";
private static final ByteChunk ENCODING = new ByteChunk();
// ----------------------------------------------------- Instance Variables
private ByteBuffer buffered;
private ByteBuffer tempRead;
private InputBuffer buffer;
private boolean hasRead = false;
// ----------------------------------------------------- Static Initializer
static {
ENCODING.setBytes(ENCODING_NAME.getBytes(StandardCharsets.ISO_8859_1),
0, ENCODING_NAME.length());
}
// --------------------------------------------------------- Public Methods
/**
* Set the buffering limit. This should be reset every time the buffer is
* used.
*
* @param limit The maximum number of bytes that will be buffered
*/
public void setLimit(int limit) {
if (buffered == null) {
buffered = ByteBuffer.allocate(limit);
buffered.flip();
}
}
// ---------------------------------------------------- InputBuffer Methods
/**
* Reads the request body and buffers it.
*/
@Override
public void setRequest(Request request) {
// save off the Request body
try {
while (buffer.doRead(this) >= 0) {
buffered.mark().position(buffered.limit()).limit(buffered.capacity());
buffered.put(tempRead);
buffered.limit(buffered.position()).reset();
tempRead = null;
}
} catch(IOException | BufferOverflowException ioe) {
// No need for i18n - this isn't going to get logged anywhere
throw new IllegalStateException(
"Request body too large for buffer");
}
}
/**
* Fills the given ByteChunk with the buffered request body.
*
* @deprecated Unused. Will be removed in Tomcat 9. Use
* {@link #doRead(ApplicationBufferHandler)}
*/
@Deprecated
@Override
public int doRead(ByteChunk chunk) throws IOException {
if (isFinished()) {
return -1;
}
chunk.setBytes(buffered.array(), buffered.arrayOffset() + buffered.position(),
buffered.remaining());
hasRead = true;
return chunk.getLength();
}
/**
* Fills the given ByteBuffer with the buffered request body.
*/
@Override
public int doRead(ApplicationBufferHandler handler) throws IOException {
if (isFinished()) {
return -1;
}
handler.setByteBuffer(buffered);
hasRead = true;
return buffered.remaining();
}
@Override
public void setBuffer(InputBuffer buffer) {
this.buffer = buffer;
}
@Override
public void recycle() {
if (buffered != null) {
if (buffered.capacity() > 65536) {
buffered = null;
} else {
buffered.position(0).limit(0);
}
}
hasRead = false;
buffer = null;
}
@Override
public ByteChunk getEncodingName() {
return ENCODING;
}
@Override
public long end() throws IOException {
return 0;
}
@Override
public int available() {
return buffered.remaining();
}
@Override
public boolean isFinished() {
return hasRead || buffered.remaining() <= 0;
}
@Override
public void setByteBuffer(ByteBuffer buffer) {
tempRead = buffer;
}
@Override
public ByteBuffer getByteBuffer() {
return tempRead;
}
@Override
public void expand(int size) {
// no-op
}
}

View File

@@ -0,0 +1,688 @@
/*
* 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.filters;
import java.io.EOFException;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.Locale;
import java.util.Set;
import org.apache.coyote.InputBuffer;
import org.apache.coyote.Request;
import org.apache.coyote.http11.Constants;
import org.apache.coyote.http11.InputFilter;
import org.apache.tomcat.util.buf.ByteChunk;
import org.apache.tomcat.util.buf.HexUtils;
import org.apache.tomcat.util.buf.MessageBytes;
import org.apache.tomcat.util.http.MimeHeaders;
import org.apache.tomcat.util.net.ApplicationBufferHandler;
import org.apache.tomcat.util.res.StringManager;
/**
* Chunked input filter. Parses chunked data according to
* <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.6.1">http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.6.1</a><br>
*
* @author Remy Maucherat
*/
public class ChunkedInputFilter implements InputFilter, ApplicationBufferHandler {
private static final StringManager sm = StringManager.getManager(
ChunkedInputFilter.class.getPackage().getName());
// -------------------------------------------------------------- Constants
protected static final String ENCODING_NAME = "chunked";
protected static final ByteChunk ENCODING = new ByteChunk();
// ----------------------------------------------------- Static Initializer
static {
ENCODING.setBytes(ENCODING_NAME.getBytes(StandardCharsets.ISO_8859_1),
0, ENCODING_NAME.length());
}
// ----------------------------------------------------- Instance Variables
/**
* Next buffer in the pipeline.
*/
protected InputBuffer buffer;
/**
* Number of bytes remaining in the current chunk.
*/
protected int remaining = 0;
/**
* Byte chunk used to read bytes.
*/
protected ByteBuffer readChunk;
/**
* Flag set to true when the end chunk has been read.
*/
protected boolean endChunk = false;
/**
* Byte chunk used to store trailing headers.
*/
protected final ByteChunk trailingHeaders = new ByteChunk();
/**
* Flag set to true if the next call to doRead() must parse a CRLF pair
* before doing anything else.
*/
protected boolean needCRLFParse = false;
/**
* Request being parsed.
*/
private Request request;
/**
* Limit for extension size.
*/
private final long maxExtensionSize;
/**
* Limit for trailer size.
*/
private final int maxTrailerSize;
/**
* Size of extensions processed for this request.
*/
private long extensionSize;
private final int maxSwallowSize;
/**
* Flag that indicates if an error has occurred.
*/
private boolean error;
private final Set<String> allowedTrailerHeaders;
// ----------------------------------------------------------- Constructors
public ChunkedInputFilter(int maxTrailerSize, Set<String> allowedTrailerHeaders,
int maxExtensionSize, int maxSwallowSize) {
this.trailingHeaders.setLimit(maxTrailerSize);
this.allowedTrailerHeaders = allowedTrailerHeaders;
this.maxExtensionSize = maxExtensionSize;
this.maxTrailerSize = maxTrailerSize;
this.maxSwallowSize = maxSwallowSize;
}
// ---------------------------------------------------- InputBuffer Methods
/**
* @deprecated Unused. Will be removed in Tomcat 9. Use
* {@link #doRead(ApplicationBufferHandler)}
*/
@Deprecated
@Override
public int doRead(ByteChunk chunk) throws IOException {
if (endChunk) {
return -1;
}
checkError();
if(needCRLFParse) {
needCRLFParse = false;
parseCRLF(false);
}
if (remaining <= 0) {
if (!parseChunkHeader()) {
throwIOException(sm.getString("chunkedInputFilter.invalidHeader"));
}
if (endChunk) {
parseEndChunk();
return -1;
}
}
int result = 0;
if (readChunk == null || readChunk.position() >= readChunk.limit()) {
if (readBytes() < 0) {
throwIOException(sm.getString("chunkedInputFilter.eos"));
}
}
if (remaining > readChunk.remaining()) {
result = readChunk.remaining();
remaining = remaining - result;
chunk.setBytes(readChunk.array(), readChunk.arrayOffset() + readChunk.position(), result);
readChunk.position(readChunk.limit());
} else {
result = remaining;
chunk.setBytes(readChunk.array(), readChunk.arrayOffset() + readChunk.position(), remaining);
readChunk.position(readChunk.position() + remaining);
remaining = 0;
//we need a CRLF
if ((readChunk.position() + 1) >= readChunk.limit()) {
//if we call parseCRLF we overrun the buffer here
//so we defer it to the next call BZ 11117
needCRLFParse = true;
} else {
parseCRLF(false); //parse the CRLF immediately
}
}
return result;
}
@Override
public int doRead(ApplicationBufferHandler handler) throws IOException {
if (endChunk) {
return -1;
}
checkError();
if(needCRLFParse) {
needCRLFParse = false;
parseCRLF(false);
}
if (remaining <= 0) {
if (!parseChunkHeader()) {
throwIOException(sm.getString("chunkedInputFilter.invalidHeader"));
}
if (endChunk) {
parseEndChunk();
return -1;
}
}
int result = 0;
if (readChunk == null || readChunk.position() >= readChunk.limit()) {
if (readBytes() < 0) {
throwIOException(sm.getString("chunkedInputFilter.eos"));
}
}
if (remaining > readChunk.remaining()) {
result = readChunk.remaining();
remaining = remaining - result;
if (readChunk != handler.getByteBuffer()) {
handler.setByteBuffer(readChunk.duplicate());
}
readChunk.position(readChunk.limit());
} else {
result = remaining;
if (readChunk != handler.getByteBuffer()) {
handler.setByteBuffer(readChunk.duplicate());
handler.getByteBuffer().limit(readChunk.position() + remaining);
}
readChunk.position(readChunk.position() + remaining);
remaining = 0;
//we need a CRLF
if ((readChunk.position() + 1) >= readChunk.limit()) {
//if we call parseCRLF we overrun the buffer here
//so we defer it to the next call BZ 11117
needCRLFParse = true;
} else {
parseCRLF(false); //parse the CRLF immediately
}
}
return result;
}
// ---------------------------------------------------- InputFilter Methods
/**
* Read the content length from the request.
*/
@Override
public void setRequest(Request request) {
this.request = request;
}
/**
* End the current request.
*/
@Override
public long end() throws IOException {
long swallowed = 0;
int read = 0;
// Consume extra bytes : parse the stream until the end chunk is found
while ((read = doRead(this)) >= 0) {
swallowed += read;
if (maxSwallowSize > -1 && swallowed > maxSwallowSize) {
throwIOException(sm.getString("inputFilter.maxSwallow"));
}
}
// Return the number of extra bytes which were consumed
return readChunk.remaining();
}
/**
* Amount of bytes still available in a buffer.
*/
@Override
public int available() {
return readChunk != null ? readChunk.remaining() : 0;
}
/**
* Set the next buffer in the filter pipeline.
*/
@Override
public void setBuffer(InputBuffer buffer) {
this.buffer = buffer;
}
/**
* Make the filter ready to process the next request.
*/
@Override
public void recycle() {
remaining = 0;
if (readChunk != null) {
readChunk.position(0).limit(0);
}
endChunk = false;
needCRLFParse = false;
trailingHeaders.recycle();
trailingHeaders.setLimit(maxTrailerSize);
extensionSize = 0;
error = false;
}
/**
* Return the name of the associated encoding; Here, the value is
* "identity".
*/
@Override
public ByteChunk getEncodingName() {
return ENCODING;
}
@Override
public boolean isFinished() {
return endChunk;
}
// ------------------------------------------------------ Protected Methods
/**
* Read bytes from the previous buffer.
* @return The byte count which has been read
* @throws IOException Read error
*/
protected int readBytes() throws IOException {
return buffer.doRead(this);
}
/**
* Parse the header of a chunk.
* A chunk header can look like one of the following:<br>
* A10CRLF<br>
* F23;chunk-extension to be ignoredCRLF
*
* <p>
* The letters before CRLF or ';' (whatever comes first) must be valid hex
* digits. We should not parse F23IAMGONNAMESSTHISUP34CRLF as a valid
* header according to the spec.
* @return <code>true</code> if the chunk header has been
* successfully parsed
* @throws IOException Read error
*/
protected boolean parseChunkHeader() throws IOException {
int result = 0;
boolean eol = false;
int readDigit = 0;
boolean extension = false;
while (!eol) {
if (readChunk == null || readChunk.position() >= readChunk.limit()) {
if (readBytes() <= 0)
return false;
}
byte chr = readChunk.get(readChunk.position());
if (chr == Constants.CR || chr == Constants.LF) {
parseCRLF(false);
eol = true;
} else if (chr == Constants.SEMI_COLON && !extension) {
// First semi-colon marks the start of the extension. Further
// semi-colons may appear to separate multiple chunk-extensions.
// These need to be processed as part of parsing the extensions.
extension = true;
extensionSize++;
} else if (!extension) {
//don't read data after the trailer
int charValue = HexUtils.getDec(chr);
if (charValue != -1 && readDigit < 8) {
readDigit++;
result = (result << 4) | charValue;
} else {
//we shouldn't allow invalid, non hex characters
//in the chunked header
return false;
}
} else {
// Extension 'parsing'
// Note that the chunk-extension is neither parsed nor
// validated. Currently it is simply ignored.
extensionSize++;
if (maxExtensionSize > -1 && extensionSize > maxExtensionSize) {
throwIOException(sm.getString("chunkedInputFilter.maxExtension"));
}
}
// Parsing the CRLF increments pos
if (!eol) {
readChunk.position(readChunk.position() + 1);
}
}
if (readDigit == 0 || result < 0) {
return false;
}
if (result == 0) {
endChunk = true;
}
remaining = result;
return true;
}
/**
* Parse CRLF at end of chunk.
*
* @param tolerant Should tolerant parsing (LF and CRLF) be used? This
* is recommended (RFC2616, section 19.3) for message
* headers.
* @throws IOException An error occurred parsing CRLF
*/
protected void parseCRLF(boolean tolerant) throws IOException {
boolean eol = false;
boolean crfound = false;
while (!eol) {
if (readChunk == null || readChunk.position() >= readChunk.limit()) {
if (readBytes() <= 0) {
throwIOException(sm.getString("chunkedInputFilter.invalidCrlfNoData"));
}
}
byte chr = readChunk.get(readChunk.position());
if (chr == Constants.CR) {
if (crfound) {
throwIOException(sm.getString("chunkedInputFilter.invalidCrlfCRCR"));
}
crfound = true;
} else if (chr == Constants.LF) {
if (!tolerant && !crfound) {
throwIOException(sm.getString("chunkedInputFilter.invalidCrlfNoCR"));
}
eol = true;
} else {
throwIOException(sm.getString("chunkedInputFilter.invalidCrlf"));
}
readChunk.position(readChunk.position() + 1);
}
}
/**
* Parse end chunk data.
* @throws IOException Error propagation
*/
protected void parseEndChunk() throws IOException {
// Handle optional trailer headers
while (parseHeader()) {
// Loop until we run out of headers
}
}
private boolean parseHeader() throws IOException {
MimeHeaders headers = request.getMimeHeaders();
byte chr = 0;
// Read new bytes if needed
if (readChunk == null || readChunk.position() >= readChunk.limit()) {
if (readBytes() <0) {
throwEOFException(sm.getString("chunkedInputFilter.eosTrailer"));
}
}
// readBytes() above will set readChunk unless it returns a value < 0
chr = readChunk.get(readChunk.position());
// CRLF terminates the request
if (chr == Constants.CR || chr == Constants.LF) {
parseCRLF(false);
return false;
}
// Mark the current buffer position
int startPos = trailingHeaders.getEnd();
//
// Reading the header name
// Header name is always US-ASCII
//
boolean colon = false;
while (!colon) {
// Read new bytes if needed
if (readChunk == null || readChunk.position() >= readChunk.limit()) {
if (readBytes() <0) {
throwEOFException(sm.getString("chunkedInputFilter.eosTrailer"));
}
}
// readBytes() above will set readChunk unless it returns a value < 0
chr = readChunk.get(readChunk.position());
if ((chr >= Constants.A) && (chr <= Constants.Z)) {
chr = (byte) (chr - Constants.LC_OFFSET);
}
if (chr == Constants.COLON) {
colon = true;
} else {
trailingHeaders.append(chr);
}
readChunk.position(readChunk.position() + 1);
}
int colonPos = trailingHeaders.getEnd();
//
// Reading the header value (which can be spanned over multiple lines)
//
boolean eol = false;
boolean validLine = true;
int lastSignificantChar = 0;
while (validLine) {
boolean space = true;
// Skipping spaces
while (space) {
// Read new bytes if needed
if (readChunk == null || readChunk.position() >= readChunk.limit()) {
if (readBytes() <0) {
throwEOFException(sm.getString("chunkedInputFilter.eosTrailer"));
}
}
chr = readChunk.get(readChunk.position());
if ((chr == Constants.SP) || (chr == Constants.HT)) {
readChunk.position(readChunk.position() + 1);
// If we swallow whitespace, make sure it counts towards the
// limit placed on trailing header size
int newlimit = trailingHeaders.getLimit() -1;
if (trailingHeaders.getEnd() > newlimit) {
throwIOException(sm.getString("chunkedInputFilter.maxTrailer"));
}
trailingHeaders.setLimit(newlimit);
} else {
space = false;
}
}
// Reading bytes until the end of the line
while (!eol) {
// Read new bytes if needed
if (readChunk == null || readChunk.position() >= readChunk.limit()) {
if (readBytes() <0) {
throwEOFException(sm.getString("chunkedInputFilter.eosTrailer"));
}
}
chr = readChunk.get(readChunk.position());
if (chr == Constants.CR || chr == Constants.LF) {
parseCRLF(true);
eol = true;
} else if (chr == Constants.SP) {
trailingHeaders.append(chr);
} else {
trailingHeaders.append(chr);
lastSignificantChar = trailingHeaders.getEnd();
}
if (!eol) {
readChunk.position(readChunk.position() + 1);
}
}
// Checking the first character of the new line. If the character
// is a LWS, then it's a multiline header
// Read new bytes if needed
if (readChunk == null || readChunk.position() >= readChunk.limit()) {
if (readBytes() <0) {
throwEOFException(sm.getString("chunkedInputFilter.eosTrailer"));
}
}
chr = readChunk.get(readChunk.position());
if ((chr != Constants.SP) && (chr != Constants.HT)) {
validLine = false;
} else {
eol = false;
// Copying one extra space in the buffer (since there must
// be at least one space inserted between the lines)
trailingHeaders.append(chr);
}
}
String headerName = new String(trailingHeaders.getBytes(), startPos,
colonPos - startPos, StandardCharsets.ISO_8859_1);
if (allowedTrailerHeaders.contains(headerName.toLowerCase(Locale.ENGLISH))) {
MessageBytes headerValue = headers.addValue(headerName);
// Set the header value
headerValue.setBytes(trailingHeaders.getBytes(), colonPos,
lastSignificantChar - colonPos);
}
return true;
}
private void throwIOException(String msg) throws IOException {
error = true;
throw new IOException(msg);
}
private void throwEOFException(String msg) throws IOException {
error = true;
throw new EOFException(msg);
}
private void checkError() throws IOException {
if (error) {
throw new IOException(sm.getString("chunkedInputFilter.error"));
}
}
@Override
public void setByteBuffer(ByteBuffer buffer) {
readChunk = buffer;
}
@Override
public ByteBuffer getByteBuffer() {
return readChunk;
}
@Override
public void expand(int size) {
// no-op
}
}

View File

@@ -0,0 +1,184 @@
/*
* 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.filters;
import java.io.IOException;
import java.nio.ByteBuffer;
import org.apache.coyote.Response;
import org.apache.coyote.http11.HttpOutputBuffer;
import org.apache.coyote.http11.OutputFilter;
import org.apache.tomcat.util.buf.ByteChunk;
import org.apache.tomcat.util.buf.HexUtils;
/**
* Chunked output filter.
*
* @author Remy Maucherat
*/
public class ChunkedOutputFilter implements OutputFilter {
// -------------------------------------------------------------- Constants
private static final byte[] END_CHUNK_BYTES = {(byte) '0', (byte) '\r', (byte) '\n',
(byte) '\r', (byte) '\n'};
// ------------------------------------------------------------ Constructor
/**
* Default constructor.
*/
public ChunkedOutputFilter() {
chunkHeader.put(8, (byte) '\r');
chunkHeader.put(9, (byte) '\n');
}
// ----------------------------------------------------- Instance Variables
/**
* Next buffer in the pipeline.
*/
protected HttpOutputBuffer buffer;
/**
* Chunk header.
*/
protected final ByteBuffer chunkHeader = ByteBuffer.allocate(10);
/**
* End chunk.
*/
protected final ByteBuffer endChunk = ByteBuffer.wrap(END_CHUNK_BYTES);
// ------------------------------------------------------------- Properties
// --------------------------------------------------- OutputBuffer Methods
/**
* @deprecated Unused. Will be removed in Tomcat 9. Use
* {@link #doWrite(ByteBuffer)}
*/
@Deprecated
@Override
public int doWrite(ByteChunk chunk) throws IOException {
int result = chunk.getLength();
if (result <= 0) {
return 0;
}
int pos = calculateChunkHeader(result);
chunkHeader.position(pos).limit(10);
buffer.doWrite(chunkHeader);
buffer.doWrite(chunk);
chunkHeader.position(8).limit(10);
buffer.doWrite(chunkHeader);
return result;
}
@Override
public int doWrite(ByteBuffer chunk) throws IOException {
int result = chunk.remaining();
if (result <= 0) {
return 0;
}
int pos = calculateChunkHeader(result);
chunkHeader.position(pos).limit(10);
buffer.doWrite(chunkHeader);
buffer.doWrite(chunk);
chunkHeader.position(8).limit(10);
buffer.doWrite(chunkHeader);
return result;
}
private int calculateChunkHeader(int len) {
// Calculate chunk header
int pos = 8;
int current = len;
while (current > 0) {
int digit = current % 16;
current = current / 16;
chunkHeader.put(--pos, HexUtils.getHex(digit));
}
return pos;
}
@Override
public long getBytesWritten() {
return buffer.getBytesWritten();
}
// --------------------------------------------------- OutputFilter Methods
@Override
public void setResponse(Response response) {
// NOOP: No need for parameters from response in this filter
}
@Override
public void setBuffer(HttpOutputBuffer buffer) {
this.buffer = buffer;
}
@Override
public void flush() throws IOException {
// No data buffered in this filter. Flush next buffer.
buffer.flush();
}
@Override
public void end() throws IOException {
// Write end chunk
buffer.doWrite(endChunk);
endChunk.position(0).limit(endChunk.capacity());
buffer.end();
}
@Override
public void recycle() {
// NOOP: Nothing to recycle
}
}

View File

@@ -0,0 +1,184 @@
/*
* 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.filters;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.util.zip.GZIPOutputStream;
import org.apache.coyote.Response;
import org.apache.coyote.http11.HttpOutputBuffer;
import org.apache.coyote.http11.OutputFilter;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
import org.apache.tomcat.util.buf.ByteChunk;
/**
* Gzip output filter.
*
* @author Remy Maucherat
*/
public class GzipOutputFilter implements OutputFilter {
protected static final Log log = LogFactory.getLog(GzipOutputFilter.class);
// ----------------------------------------------------- Instance Variables
/**
* Next buffer in the pipeline.
*/
protected HttpOutputBuffer buffer;
/**
* Compression output stream.
*/
protected GZIPOutputStream compressionStream = null;
/**
* Fake internal output stream.
*/
protected final OutputStream fakeOutputStream = new FakeOutputStream();
// --------------------------------------------------- OutputBuffer Methods
/**
* @deprecated Unused. Will be removed in Tomcat 9. Use
* {@link #doWrite(ByteBuffer)}
*/
@Deprecated
@Override
public int doWrite(ByteChunk chunk) throws IOException {
if (compressionStream == null) {
compressionStream = new GZIPOutputStream(fakeOutputStream, true);
}
compressionStream.write(chunk.getBytes(), chunk.getStart(),
chunk.getLength());
return chunk.getLength();
}
@Override
public int doWrite(ByteBuffer chunk) throws IOException {
if (compressionStream == null) {
compressionStream = new GZIPOutputStream(fakeOutputStream, true);
}
int len = chunk.remaining();
if (chunk.hasArray()) {
compressionStream.write(chunk.array(), chunk.arrayOffset() + chunk.position(), len);
} else {
byte[] bytes = new byte[len];
chunk.put(bytes);
compressionStream.write(bytes, 0, len);
}
return len;
}
@Override
public long getBytesWritten() {
return buffer.getBytesWritten();
}
// --------------------------------------------------- OutputFilter Methods
/**
* Added to allow flushing to happen for the gzip'ed outputstream
*/
@Override
public void flush() throws IOException {
if (compressionStream != null) {
try {
if (log.isDebugEnabled()) {
log.debug("Flushing the compression stream!");
}
compressionStream.flush();
} catch (IOException e) {
if (log.isDebugEnabled()) {
log.debug("Ignored exception while flushing gzip filter", e);
}
}
}
buffer.flush();
}
@Override
public void setResponse(Response response) {
// NOOP: No need for parameters from response in this filter
}
@Override
public void setBuffer(HttpOutputBuffer buffer) {
this.buffer = buffer;
}
@Override
public void end() throws IOException {
if (compressionStream == null) {
compressionStream = new GZIPOutputStream(fakeOutputStream, true);
}
compressionStream.finish();
compressionStream.close();
buffer.end();
}
/**
* Make the filter ready to process the next request.
*/
@Override
public void recycle() {
// Set compression stream to null
compressionStream = null;
}
// ------------------------------------------- FakeOutputStream Inner Class
protected class FakeOutputStream
extends OutputStream {
protected final ByteBuffer outputChunk = ByteBuffer.allocate(1);
@Override
public void write(int b)
throws IOException {
// Shouldn't get used for good performance, but is needed for
// compatibility with Sun JDK 1.4.0
outputChunk.put(0, (byte) (b & 0xff));
buffer.doWrite(outputChunk);
}
@Override
public void write(byte[] b, int off, int len)
throws IOException {
buffer.doWrite(ByteBuffer.wrap(b, off, len));
}
@Override
public void flush() throws IOException {/*NOOP*/}
@Override
public void close() throws IOException {/*NOOP*/}
}
}

View File

@@ -0,0 +1,274 @@
/*
* 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.filters;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import org.apache.coyote.InputBuffer;
import org.apache.coyote.Request;
import org.apache.coyote.http11.InputFilter;
import org.apache.tomcat.util.buf.ByteChunk;
import org.apache.tomcat.util.net.ApplicationBufferHandler;
import org.apache.tomcat.util.res.StringManager;
/**
* Identity input filter.
*
* @author Remy Maucherat
*/
public class IdentityInputFilter implements InputFilter, ApplicationBufferHandler {
private static final StringManager sm = StringManager.getManager(
IdentityInputFilter.class.getPackage().getName());
// -------------------------------------------------------------- Constants
protected static final String ENCODING_NAME = "identity";
protected static final ByteChunk ENCODING = new ByteChunk();
// ----------------------------------------------------- Static Initializer
static {
ENCODING.setBytes(ENCODING_NAME.getBytes(StandardCharsets.ISO_8859_1),
0, ENCODING_NAME.length());
}
// ----------------------------------------------------- Instance Variables
/**
* Content length.
*/
protected long contentLength = -1;
/**
* Remaining bytes.
*/
protected long remaining = 0;
/**
* Next buffer in the pipeline.
*/
protected InputBuffer buffer;
/**
* ByteBuffer used to read leftover bytes.
*/
protected ByteBuffer tempRead;
private final int maxSwallowSize;
public IdentityInputFilter(int maxSwallowSize) {
this.maxSwallowSize = maxSwallowSize;
}
// ---------------------------------------------------- InputBuffer Methods
/**
* @deprecated Unused. Will be removed in Tomcat 9. Use
* {@link #doRead(ApplicationBufferHandler)}
*/
@Deprecated
@Override
public int doRead(ByteChunk chunk) throws IOException {
int result = -1;
if (contentLength >= 0) {
if (remaining > 0) {
int nRead = buffer.doRead(chunk);
if (nRead > remaining) {
// The chunk is longer than the number of bytes remaining
// in the body; changing the chunk length to the number
// of bytes remaining
chunk.setBytes(chunk.getBytes(), chunk.getStart(),
(int) remaining);
result = (int) remaining;
} else {
result = nRead;
}
if (nRead > 0) {
remaining = remaining - nRead;
}
} else {
// No more bytes left to be read : return -1 and clear the
// buffer
chunk.recycle();
result = -1;
}
}
return result;
}
@Override
public int doRead(ApplicationBufferHandler handler) throws IOException {
int result = -1;
if (contentLength >= 0) {
if (remaining > 0) {
int nRead = buffer.doRead(handler);
if (nRead > remaining) {
// The chunk is longer than the number of bytes remaining
// in the body; changing the chunk length to the number
// of bytes remaining
handler.getByteBuffer().limit(handler.getByteBuffer().position() + (int) remaining);
result = (int) remaining;
} else {
result = nRead;
}
if (nRead > 0) {
remaining = remaining - nRead;
}
} else {
// No more bytes left to be read : return -1 and clear the
// buffer
if (handler.getByteBuffer() != null) {
handler.getByteBuffer().position(0).limit(0);
}
result = -1;
}
}
return result;
}
// ---------------------------------------------------- InputFilter Methods
/**
* Read the content length from the request.
*/
@Override
public void setRequest(Request request) {
contentLength = request.getContentLengthLong();
remaining = contentLength;
}
@Override
public long end() throws IOException {
final boolean maxSwallowSizeExceeded = (maxSwallowSize > -1 && remaining > maxSwallowSize);
long swallowed = 0;
// Consume extra bytes.
while (remaining > 0) {
int nread = buffer.doRead(this);
tempRead = null;
if (nread > 0 ) {
swallowed += nread;
remaining = remaining - nread;
if (maxSwallowSizeExceeded && swallowed > maxSwallowSize) {
// Note: We do not fail early so the client has a chance to
// read the response before the connection is closed. See:
// https://httpd.apache.org/docs/2.0/misc/fin_wait_2.html#appendix
throw new IOException(sm.getString("inputFilter.maxSwallow"));
}
} else { // errors are handled higher up.
remaining = 0;
}
}
// If too many bytes were read, return the amount.
return -remaining;
}
/**
* Amount of bytes still available in a buffer.
*/
@Override
public int available() {
return 0;
}
/**
* Set the next buffer in the filter pipeline.
*/
@Override
public void setBuffer(InputBuffer buffer) {
this.buffer = buffer;
}
/**
* Make the filter ready to process the next request.
*/
@Override
public void recycle() {
contentLength = -1;
remaining = 0;
}
/**
* Return the name of the associated encoding; Here, the value is
* "identity".
*/
@Override
public ByteChunk getEncodingName() {
return ENCODING;
}
@Override
public boolean isFinished() {
// Only finished if a content length is defined and there is no data
// remaining
return contentLength > -1 && remaining <= 0;
}
@Override
public void setByteBuffer(ByteBuffer buffer) {
tempRead = buffer;
}
@Override
public ByteBuffer getByteBuffer() {
return tempRead;
}
@Override
public void expand(int size) {
// no-op
}
}

View File

@@ -0,0 +1,175 @@
/*
* 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.filters;
import java.io.IOException;
import java.nio.ByteBuffer;
import org.apache.coyote.Response;
import org.apache.coyote.http11.HttpOutputBuffer;
import org.apache.coyote.http11.OutputFilter;
import org.apache.tomcat.util.buf.ByteChunk;
/**
* Identity output filter.
*
* @author Remy Maucherat
*/
public class IdentityOutputFilter implements OutputFilter {
// ----------------------------------------------------- Instance Variables
/**
* Content length.
*/
protected long contentLength = -1;
/**
* Remaining bytes.
*/
protected long remaining = 0;
/**
* Next buffer in the pipeline.
*/
protected HttpOutputBuffer buffer;
// --------------------------------------------------- OutputBuffer Methods
/**
* @deprecated Unused. Will be removed in Tomcat 9. Use
* {@link #doWrite(ByteBuffer)}
*/
@Deprecated
@Override
public int doWrite(ByteChunk chunk) throws IOException {
int result = -1;
if (contentLength >= 0) {
if (remaining > 0) {
result = chunk.getLength();
if (result > remaining) {
// The chunk is longer than the number of bytes remaining
// in the body; changing the chunk length to the number
// of bytes remaining
chunk.setBytes(chunk.getBytes(), chunk.getStart(),
(int) remaining);
result = (int) remaining;
remaining = 0;
} else {
remaining = remaining - result;
}
buffer.doWrite(chunk);
} else {
// No more bytes left to be written : return -1 and clear the
// buffer
chunk.recycle();
result = -1;
}
} else {
// If no content length was set, just write the bytes
buffer.doWrite(chunk);
result = chunk.getLength();
}
return result;
}
@Override
public int doWrite(ByteBuffer chunk) throws IOException {
int result = -1;
if (contentLength >= 0) {
if (remaining > 0) {
result = chunk.remaining();
if (result > remaining) {
// The chunk is longer than the number of bytes remaining
// in the body; changing the chunk length to the number
// of bytes remaining
chunk.limit(chunk.position() + (int) remaining);
result = (int) remaining;
remaining = 0;
} else {
remaining = remaining - result;
}
buffer.doWrite(chunk);
} else {
// No more bytes left to be written : return -1 and clear the
// buffer
chunk.position(0);
chunk.limit(0);
result = -1;
}
} else {
// If no content length was set, just write the bytes
result = chunk.remaining();
buffer.doWrite(chunk);
result -= chunk.remaining();
}
return result;
}
@Override
public long getBytesWritten() {
return buffer.getBytesWritten();
}
// --------------------------------------------------- OutputFilter Methods
@Override
public void setResponse(Response response) {
contentLength = response.getContentLengthLong();
remaining = contentLength;
}
@Override
public void setBuffer(HttpOutputBuffer buffer) {
this.buffer = buffer;
}
@Override
public void flush() throws IOException {
// No data buffered in this filter. Flush next buffer.
buffer.flush();
}
@Override
public void end() throws IOException {
buffer.end();
}
@Override
public void recycle() {
contentLength = -1;
remaining = 0;
}
}

View File

@@ -0,0 +1,27 @@
# 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.
chunkedInputFilter.eos=Unexpected end of stream while reading request body
chunkedInputFilter.eosTrailer=Unexpected end of stream while reading trailer headers
chunkedInputFilter.error=No data available due to previous error
chunkedInputFilter.invalidCrlf=Invalid end of line sequence (character other than CR or LF found)
chunkedInputFilter.invalidCrlfCRCR=Invalid end of line sequence (CRCR)
chunkedInputFilter.invalidCrlfNoCR=Invalid end of line sequence (No CR before LF)
chunkedInputFilter.invalidCrlfNoData=Invalid end of line sequence (no data available to read)
chunkedInputFilter.invalidHeader=Invalid chunk header
chunkedInputFilter.maxExtension=maxExtensionSize exceeded
chunkedInputFilter.maxTrailer=maxTrailerSize exceeded
inputFilter.maxSwallow=maxSwallowSize exceeded

View File

@@ -0,0 +1,18 @@
# 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.
chunkedInputFilter.eos=Unerwartetes Ende des Streams beim lesen des Request Bodys.
chunkedInputFilter.eosTrailer=Unerwartetes Ende des Eingabestroms während die Trailer-Header gelesen wurden
chunkedInputFilter.invalidCrlfNoCR=Falsche Buchstabensequenz für Zeilenende (richtig wäre <CR><LF>)

View File

@@ -0,0 +1,18 @@
# 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.
chunkedInputFilter.eos=Fin del flujo inesperado mientras se leía la petición del cuerpo
chunkedInputFilter.eosTrailer=Fin inesperado de stream mintras se leían las cabeceras finales
chunkedInputFilter.invalidCrlfNoCR=Fin de linea incorrecto (CR no debe estar antes de LF)

View File

@@ -0,0 +1,27 @@
# 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.
chunkedInputFilter.eos=Fin du flux inattendue durant la lecture du corps de la requête
chunkedInputFilter.eosTrailer=Fin inattendue de flux lors de la lecture des en-têtes de fin (trailer headers)
chunkedInputFilter.error=Aucune donnée disponible suite à l'erreur précédente
chunkedInputFilter.invalidCrlf=Séquence de fin de ligne invalide, un caractère autre que CR ou LF a été trouvé
chunkedInputFilter.invalidCrlfCRCR=Séquence de fin de ligne invalide, CR CR
chunkedInputFilter.invalidCrlfNoCR=Terminateur de ligne incorrect (manque CR devant LF)
chunkedInputFilter.invalidCrlfNoData=Séquence de fin de ligne invalide (aucune donnée disponible en lecture)
chunkedInputFilter.invalidHeader=En-tête de morceau (chunk) invalide
chunkedInputFilter.maxExtension=maxExtensionSize a été dépassé
chunkedInputFilter.maxTrailer=maxTrailerSize a été dépassé
inputFilter.maxSwallow=maxSwallowSize a été dépassé

View File

@@ -0,0 +1,27 @@
# 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.
chunkedInputFilter.eos=リクエストボディの読み取り中に予期せぬストリームの終端が見つかりました。
chunkedInputFilter.eosTrailer=トレーラーヘッダーの読み込み中に突然ストリームが終了しました。
chunkedInputFilter.error=以前のエラーのため利用できるデータがありません。
chunkedInputFilter.invalidCrlf=無効なEOLシーケンスCRまたはLF以外の文字が見つかりました
chunkedInputFilter.invalidCrlfCRCR=無効なEOLシーケンスCRCR
chunkedInputFilter.invalidCrlfNoCR=不正な改行コードです (LFの前にCRがありません)。
chunkedInputFilter.invalidCrlfNoData=無効なEOL順序読み込み可能なデータがありません
chunkedInputFilter.invalidHeader=不正なチャンクヘッダーです。
chunkedInputFilter.maxExtension=maxExtensionSizeを超過しました
chunkedInputFilter.maxTrailer=maxTrailerSize を超過しています。
inputFilter.maxSwallow=maxShallowSize を超えました。

View File

@@ -0,0 +1,27 @@
# 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.
chunkedInputFilter.eos=요청의 body를 읽는 동안 예기치 않은 스트림의 끝
chunkedInputFilter.eosTrailer=Trailer 헤더들을 읽는 중 예기치 않은 스트림의 끝
chunkedInputFilter.error=이전 오류로 인하여 데이터가 가용하지 않습니다.
chunkedInputFilter.invalidCrlf=유효하지 않은 행의 끝 시퀀스입니다. (CR 또는 LF가 아닌 다른 문자가 발견됨)
chunkedInputFilter.invalidCrlfCRCR=유효하지 않은 행의 끝 시퀀스 (CRCR)
chunkedInputFilter.invalidCrlfNoCR=유효하지 않은 라인 끝 시퀀스 (CR 바이트가 LF 바이트 전에 존재하지 않음)
chunkedInputFilter.invalidCrlfNoData=유효하지 않은 행의 끝 시퀀스 (더 이상 읽을 데이터가 없음)
chunkedInputFilter.invalidHeader=유효하지 않은 chunk 헤더
chunkedInputFilter.maxExtension=maxExtensionSize 값을 초과했습니다.
chunkedInputFilter.maxTrailer=maxTrailerSize 값을 초과했습니다.
inputFilter.maxSwallow=maxSwallowSize 값을 초과했습니다.

View File

@@ -0,0 +1,25 @@
# 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.
chunkedInputFilter.eos=读取请求主体时流的意外结束
chunkedInputFilter.eosTrailer=读取 trailer 头时出现意外的流结束
chunkedInputFilter.error=没有数据可用由于先前的错误
chunkedInputFilter.invalidCrlfCRCR=无效的结束的行序列CRCR)
chunkedInputFilter.invalidCrlfNoCR=无效的行尾结束符序列(LF前缺少CR)
chunkedInputFilter.invalidCrlfNoData=无效的行尾序列(没有可读取的数据)
chunkedInputFilter.maxExtension=超过最大扩展数
chunkedInputFilter.maxTrailer=超过最大数
inputFilter.maxSwallow=最大吞咽数据大小超出异常

View File

@@ -0,0 +1,137 @@
/*
* 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.filters;
import java.io.IOException;
import java.nio.ByteBuffer;
import org.apache.coyote.InputBuffer;
import org.apache.coyote.http11.InputFilter;
import org.apache.tomcat.util.buf.ByteChunk;
import org.apache.tomcat.util.net.ApplicationBufferHandler;
/**
* Input filter responsible for replaying the request body when restoring the
* saved request after FORM authentication.
*/
public class SavedRequestInputFilter implements InputFilter {
/**
* The original request body.
*/
protected ByteChunk input = null;
/**
* Create a new SavedRequestInputFilter.
*
* @param input The saved request body to be replayed.
*/
public SavedRequestInputFilter(ByteChunk input) {
this.input = input;
}
/**
* @deprecated Unused. Will be removed in Tomcat 9. Use
* {@link #doRead(ApplicationBufferHandler)}
*/
@Deprecated
@Override
public int doRead(ByteChunk chunk) throws IOException {
if(input.getOffset()>= input.getEnd())
return -1;
int writeLength = 0;
if (chunk.getLimit() > 0 && chunk.getLimit() < input.getLength()) {
writeLength = chunk.getLimit();
} else {
writeLength = input.getLength();
}
input.substract(chunk.getBuffer(), 0, writeLength);
chunk.setOffset(0);
chunk.setEnd(writeLength);
return writeLength;
}
@Override
public int doRead(ApplicationBufferHandler handler) throws IOException {
if(input.getOffset()>= input.getEnd())
return -1;
ByteBuffer byteBuffer = handler.getByteBuffer();
byteBuffer.position(byteBuffer.limit()).limit(byteBuffer.capacity());
input.substract(byteBuffer);
return byteBuffer.remaining();
}
/**
* Set the content length on the request.
*/
@Override
public void setRequest(org.apache.coyote.Request request) {
request.setContentLength(input.getLength());
}
/**
* Make the filter ready to process the next request.
*/
@Override
public void recycle() {
input = null;
}
/**
* Return the name of the associated encoding; here, the value is null.
*/
@Override
public ByteChunk getEncodingName() {
return null;
}
/**
* Set the next buffer in the filter pipeline (has no effect).
*/
@Override
public void setBuffer(InputBuffer buffer) {
// NOOP since this filter will be providing the request body
}
/**
* Amount of bytes still available in a buffer.
*/
@Override
public int available() {
return input.getLength();
}
/**
* End the current request (has no effect).
*/
@Override
public long end() throws IOException {
return 0;
}
@Override
public boolean isFinished() {
return input.getOffset() >= input.getEnd();
}
}

View File

@@ -0,0 +1,133 @@
/*
* 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.filters;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import org.apache.coyote.InputBuffer;
import org.apache.coyote.Request;
import org.apache.coyote.http11.InputFilter;
import org.apache.tomcat.util.buf.ByteChunk;
import org.apache.tomcat.util.net.ApplicationBufferHandler;
/**
* Void input filter, which returns -1 when attempting a read. Used with a GET,
* HEAD, or a similar request.
*
* @author Remy Maucherat
*/
public class VoidInputFilter implements InputFilter {
// -------------------------------------------------------------- Constants
protected static final String ENCODING_NAME = "void";
protected static final ByteChunk ENCODING = new ByteChunk();
// ----------------------------------------------------- Static Initializer
static {
ENCODING.setBytes(ENCODING_NAME.getBytes(StandardCharsets.ISO_8859_1),
0, ENCODING_NAME.length());
}
// ---------------------------------------------------- InputBuffer Methods
/**
* @deprecated Unused. Will be removed in Tomcat 9. Use
* {@link #doRead(ApplicationBufferHandler)}
*/
@Deprecated
@Override
public int doRead(ByteChunk chunk) throws IOException {
return -1;
}
@Override
public int doRead(ApplicationBufferHandler handler) throws IOException {
return -1;
}
// ---------------------------------------------------- InputFilter Methods
/**
* Set the associated request.
*/
@Override
public void setRequest(Request request) {
// NOOP: Request isn't used so ignore it
}
/**
* Set the next buffer in the filter pipeline.
*/
@Override
public void setBuffer(InputBuffer buffer) {
// NOOP: No body to read
}
/**
* Make the filter ready to process the next request.
*/
@Override
public void recycle() {
// NOOP
}
/**
* Return the name of the associated encoding; Here, the value is
* "void".
*/
@Override
public ByteChunk getEncodingName() {
return ENCODING;
}
/**
* End the current request. It is acceptable to write extra bytes using
* buffer.doWrite during the execution of this method.
*
* @return Should return 0 unless the filter does some content length
* delimitation, in which case the number is the amount of extra bytes or
* missing bytes, which would indicate an error.
* Note: It is recommended that extra bytes be swallowed by the filter.
*/
@Override
public long end() throws IOException {
return 0;
}
@Override
public int available() {
return 0;
}
@Override
public boolean isFinished() {
return true;
}
}

View File

@@ -0,0 +1,93 @@
/*
* 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.filters;
import java.io.IOException;
import java.nio.ByteBuffer;
import org.apache.coyote.Response;
import org.apache.coyote.http11.HttpOutputBuffer;
import org.apache.coyote.http11.OutputFilter;
import org.apache.tomcat.util.buf.ByteChunk;
/**
* Void output filter, which silently swallows bytes written. Used with a 204
* status (no content) or a HEAD request.
*
* @author Remy Maucherat
*/
public class VoidOutputFilter implements OutputFilter {
private HttpOutputBuffer buffer = null;
// --------------------------------------------------- OutputBuffer Methods
/**
* @deprecated Unused. Will be removed in Tomcat 9. Use
* {@link #doWrite(ByteBuffer)}
*/
@Deprecated
@Override
public int doWrite(ByteChunk chunk) throws IOException {
return chunk.getLength();
}
@Override
public int doWrite(ByteBuffer chunk) throws IOException {
return chunk.remaining();
}
@Override
public long getBytesWritten() {
return 0;
}
// --------------------------------------------------- OutputFilter Methods
@Override
public void setResponse(Response response) {
// NOOP: No need for parameters from response in this filter
}
@Override
public void setBuffer(HttpOutputBuffer buffer) {
this.buffer = buffer;
}
@Override
public void flush() throws IOException {
this.buffer.flush();
}
@Override
public void recycle() {
buffer = null;
}
@Override
public void end() throws IOException {
buffer.end();
}
}

View File

@@ -0,0 +1,42 @@
/*
* 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.upgrade;
import javax.servlet.http.HttpUpgradeHandler;
import org.apache.tomcat.util.net.AbstractEndpoint.Handler.SocketState;
import org.apache.tomcat.util.net.SSLSupport;
import org.apache.tomcat.util.net.SocketEvent;
import org.apache.tomcat.util.net.SocketWrapperBase;
/**
* This Tomcat specific interface is implemented by handlers that require direct
* access to Tomcat's I/O layer rather than going through the Servlet API.
*/
public interface InternalHttpUpgradeHandler extends HttpUpgradeHandler {
SocketState upgradeDispatch(SocketEvent status);
void timeoutAsync(long now);
void setSocketWrapper(SocketWrapperBase<?> wrapper);
void setSslSupport(SSLSupport sslSupport);
void pause();
}

View File

@@ -0,0 +1,36 @@
# 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.
upgrade.sis.errorCloseFail=Failed to close InputStream cleanly after a previous error
upgrade.sis.isFinished.ise=It is illegal to call isFinished() when the ServletInputStream is not in non-blocking mode (i.e. setReadListener() must be called first)
upgrade.sis.isReady.ise=It is illegal to call isReady() when the ServletInputStream is not in non-blocking mode (i.e. setReadListener() must be called first)
upgrade.sis.onErrorFail=onError processing for the registered ReadListener triggered this further error which was swallowed
upgrade.sis.read.closed=The InputStream has been closed
upgrade.sis.read.ise=It is illegal to call any of the read() methods in non-blocking mode without first checking that there is data available by calling isReady()
upgrade.sis.readListener.null=It is illegal to pass null to setReadListener()
upgrade.sis.readListener.set=It is illegal to call setReadListener() more than once for the same upgraded connection
upgrade.sos.canWrite.ise=It is illegal to call canWrite() when the ServletOutputStream is not in non-blocking mode (i.e. setWriteListener() must be called first)
upgrade.sos.errorCloseFail=Failed to close OutputStream cleanly after a previous error
upgrade.sos.onErrorFail=onError processing for the registered WriteListener triggered this further error which was swallowed
upgrade.sos.write.closed=The OutputStream has been closed
upgrade.sos.write.ise=It is illegal to call any of the write() methods in non-blocking mode without first checking that there is space available by calling isReady()
upgrade.sos.writeListener.null=It is illegal to pass null to setWriteListener()
upgrade.sos.writeListener.set=It is illegal to call setWriteListener() more than once for the same upgraded connection
upgradeProcessor.isCloseFail=Failed to close input stream associated with upgraded connection
upgradeProcessor.osCloseFail=Failed to close output stream associated with upgraded connection
upgradeProcessor.requiredClose=Closing upgraded connection due to closeRequired state of streams: Input [{0}], Output [{1}]
upgradeProcessor.stop=Closing upgraded connection as incoming socket status was STOP
upgradeProcessor.unexpectedState=Closing upgraded connection unexpectedly as incoming socket status was [{0}]

View File

@@ -0,0 +1,18 @@
# 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.
upgrade.sis.read.closed=Der InputStream wurde geschlossen.
upgrade.sis.readListener.set=setReadListener() darf nicht mehr als einmal für eine Upgraded-Verbindung aufgerufen werden
upgrade.sos.writeListener.null=setWriteListener() darf nicht mit null aufgerufen werden

View File

@@ -0,0 +1,20 @@
# 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.
upgrade.sis.read.closed=El InputStream ha sido cerrado.
upgrade.sis.readListener.set=Es ilegal llamar a setReadListener() más de una vez para la misma conexión actualizada\n
upgrade.sos.writeListener.null=Es ilegal pasar valor nulo a setWriteListener()\n
upgradeProcessor.unexpectedState=Cerrando la conexión actualizada inesperadamente debido al que el estatus del socket fue [{0}]\n

View File

@@ -0,0 +1,36 @@
# 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.
upgrade.sis.errorCloseFail=Impossible de fermer l'InputStream proprement après une précédente erreur
upgrade.sis.isFinished.ise=Il est illégal d'appeler isFinished() quand le ServletInputStream n'est pas en mode non bloquant, c'est à dire que setReadListener() doit d'abord être appelé
upgrade.sis.isReady.ise=il est illégal d'appeler isReady() quand le ServletInputStream n'est pas en mode non bloquant, c'est à dire que setReadListener() doit d'abord être appelé
upgrade.sis.onErrorFail=Le traitement de onError pour le ReadListener configuré a causé cette erreur qui a été avalée
upgrade.sis.read.closed=Le flux d'entrée (InputStream) a été fermé
upgrade.sis.read.ise=Il est interdit d'appeler une des méthodes read() en mode non bloquant avant de d'abord vérifier qu'il y a des données disponibles en utilisant isReady()
upgrade.sis.readListener.null=Il est illégal de passer un argument null à setReadListener()
upgrade.sis.readListener.set=Il est interdit d'appeler setReadListener() plus d'une fois pour une même connection upgradée
upgrade.sos.canWrite.ise=il est illégal d'appeler canWrite() quand le ServletOutputStream n'est pas en mode non bloquant, c'est à dire que setWriteListener() doit d'abord être appelé
upgrade.sos.errorCloseFail=Impossible de fermer l'OutputStream proprement après une précédente erreur
upgrade.sos.onErrorFail=Le traitement de onError pour le WriteListener configuré a causé cette erreur qui a été avalée
upgrade.sos.write.closed=L'OutputSteam a été fermée
upgrade.sos.write.ise=Il est interdit d'appeler une des méthodes write() en mode non bloquant avant de d'abord vérifier qu'il y a de la place disponible en utilisant isReady()
upgrade.sos.writeListener.null=Il est illégal de passer un argument null à setWriteListener()
upgrade.sos.writeListener.set=Il est interdit d'appeler setWriteListener() plus d'une fois pour une même connection upgradée
upgradeProcessor.isCloseFail=Impossible de fermer l'InputStream associée avec la connection upgradée
upgradeProcessor.osCloseFail=Impossible de fermer l'OutputStream associée avec la connection upgradée
upgradeProcessor.requiredClose=Fermeture de la connection upgradée à cause de l''état du closeRequired des flux: Entrée [{0}] Sortie [{1}]
upgradeProcessor.stop=Fermeture de la connection upgradée car l'état du socket est STOP
upgradeProcessor.unexpectedState=Fermeture inattendue de la connection upgradée alors que le statut du socket en lecture est [{0}]

View File

@@ -0,0 +1,36 @@
# 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.
upgrade.sis.errorCloseFail=直前のエラーの後に完全にInputStreamを閉じることができませんでした。
upgrade.sis.isFinished.ise=ノンブロッキングモードではない ServletInputStream の isFinished() を呼び出すことはできません。(すなわち最初に setReadListener() を呼び出さなければなりません。)
upgrade.sis.isReady.ise=ServletInputStreamが非ブロッキングモードでない場合つまり、最初にsetReadListener()を呼び出さなければならない場合isReady()を呼び出すことはできません。
upgrade.sis.onErrorFail=登録されたReadListenerのonError処理により、さらなるエラーがトリガされました。エラーは飲み込まれました。
upgrade.sis.read.closed=InputStream はすでに切断されています。
upgrade.sis.read.ise=isReady()を呼び出すことによって利用可能なデータがあることを最初にチェックすることなく、非ブロックモードでread()メソッドを呼び出すことは不正です。
upgrade.sis.readListener.null=setReadListener() には null を指定できません。
upgrade.sis.readListener.set=アップグレードしたコネクションに何度も setReadListener() を呼び出すのは不正な操作です。
upgrade.sos.canWrite.ise=ServletOutputStreamが非ブロッキングモードでない場合つまり、setWriteListener()を最初に呼び出さなければならない場合、canWrite()を呼び出すことはできません。
upgrade.sos.errorCloseFail=以前のエラーの後にOutputStreamをきれいに閉じることができませんでした。
upgrade.sos.onErrorFail=登録されたWriteListenerのonError処理により、これがトリガされました。さらなるエラーは飲み込まれました。
upgrade.sos.write.closed=OutputStreamはクローズされました
upgrade.sos.write.ise=ノンブロッキングモードでは初めに isReady() を呼び出して利用可能な領域があることを確かめなければ、あらゆる write() メソッドの呼び出しは不正になります。
upgrade.sos.writeListener.null=setWriteListener() に null を渡すのは不正な操作です。
upgrade.sos.writeListener.set=同じアップグレードされたコネクションに対してsetWriteListener()を複数回呼び出すことはできません。
upgradeProcessor.isCloseFail=アップグレードされたコネクションに関連する入力ストリームを閉じることができませんでした。
upgradeProcessor.osCloseFail=アップグレードされた接続に関連する出力ストリームを閉じることができませんでした
upgradeProcessor.requiredClose=ストリームのcloseRequired状態によるアップグレードされた接続のクローズ入力[{0}]、出力[{1}]
upgradeProcessor.stop=到着したソケットステータスがSTOPであるためにアップグレードされたコネクションを閉じます。
upgradeProcessor.unexpectedState=ソケットの状態は [{0}] でしたがアップグレードしたコネクションは予期せぬ理由で切断しました。

View File

@@ -0,0 +1,36 @@
# 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.
upgrade.sis.errorCloseFail=이전 오류 발생 이후, InputStream을 깨끗하게 닫지 못했습니다.
upgrade.sis.isFinished.ise=ServletInputStream이 non-blocking 모드 안에 있지 않을 때, isFinished()를 호출하는 것은 불허됩니다. (즉, setReadListener()가 먼저 호출되어야만 합니다.)
upgrade.sis.isReady.ise=ServletInputStream이 non-blocking 모드 안에 있지 않을 때, isReady()를 호출하는 것은 불허됩니다. (즉 setReadListener()가 반드시 먼저 호출되어야 합니다.)
upgrade.sis.onErrorFail=등록된 ReadListener를 위한 onError 처리가 더많은 오류를 유발시켰습니다. 이 추가 오류는 별도로 표출되지 않습니다.
upgrade.sis.read.closed=InputStream은 이미 닫혀 있습니다.
upgrade.sis.read.ise=Non-blocking 모드에서는, 먼저 isReady()를 호출하여 가용한 데이터가 있는지 여부를 점검하지 않은 상태에서, 어떤 종류의 read() 메소드라도 호출하는 것은 불허됩니다.
upgrade.sis.readListener.null=setReadListener()에 널을 넘기는 것은 불허됩니다.
upgrade.sis.readListener.set=업그레이드된 동일한 연결을 위해, setReadListener()를 두 번 이상 호출하는 것은 불허됩니다.
upgrade.sos.canWrite.ise=ServletOutputStream이 non-blocking 모드 안에 있지 않을 때, canWrite()를 호출하는 것은 불허됩니다. (즉 setWriteListener()가 반드시 먼저 호출되어야 합니다.)
upgrade.sos.errorCloseFail=이전 오류 발생 이후, OutputStream을 깨끗하게 닫지 못했습니다.
upgrade.sos.onErrorFail=등록된 WriteListener를 위한 onError 처리가 이 오류를 더 유발시켰습니다. 이 추가 오류는 별도로 표출되지 않습니다.
upgrade.sos.write.closed=OutputStream이 이미 닫혀 있습니다.
upgrade.sos.write.ise=Non-blocking 모드에서는, 먼저 isReady()를 호출하여 공간이 남아있는지 점검하지 않고, 어떤 종류의 write() 메소드들을 호출하는 것은 불허됩니다.
upgrade.sos.writeListener.null=setWriteListener() 호출 시, 널을 넘기는 것은 불허됩니다.
upgrade.sos.writeListener.set=동일한 업그레이드된 연결에 대하여, setWriteListener()를 두번 이상 호출하는 것은 불허됩니다.
upgradeProcessor.isCloseFail=업그레이드된 연결과 연관된 입력 스트림을 닫지 못했습니다.
upgradeProcessor.osCloseFail=업그레이드된 연결과 연관된 출력 스트림을 닫지 못했습니다.
upgradeProcessor.requiredClose=스트림들의 closeRequired 상태로 인하여, 업그레이드된 연결을 닫습니다: 입력 [{0}], 출력 [{1}]
upgradeProcessor.stop=Incoming 소켓의 상태가 STOP임에 따라, 업그레이드된 연결을 닫습니다.
upgradeProcessor.unexpectedState=Incoming 소켓의 상태가 [{0}](이)라서, 업그레이드된 연결을 예기치 않게 종료합니다.

View File

@@ -0,0 +1,16 @@
# 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.
upgrade.sis.read.closed=InputStream был закрыт

View File

@@ -0,0 +1,26 @@
# 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.
upgrade.sis.isFinished.ise=当 ServletInputStream 不处于非阻塞模式时调用 isFinished() 是非法的(即必须首先调用 setReadListener()
upgrade.sis.onErrorFail=对注册的readlistener的错误处理触发了这个进一步的错误该错误被吞入
upgrade.sis.read.closed=InputStream 已被关闭
upgrade.sis.read.ise=在非阻塞模式下调用任何read()方法而不首先通过调用isready()检查是否有可用的数据是非法的
upgrade.sis.readListener.set=在同一个upgraded连接上调用多次setReadListener()函数是非法的
upgrade.sos.onErrorFail=对注册的WriteListener 的错误处理触发了这个进一步的错误,该错误被吞入
upgrade.sos.write.closed=输出流已被关闭
upgrade.sos.write.ise=在非阻塞模式下调用任何写()方法都是非法的而无需首先检查是否有可用的空间只需调用isreadi()
upgrade.sos.writeListener.null=对setWriteListener()传递null是非法的
upgradeProcessor.unexpectedState=因传入套接字状态为[{0}]而意外关闭升级连接

View File

@@ -0,0 +1,105 @@
/*
* 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.upgrade;
import java.io.IOException;
import java.nio.ByteBuffer;
import javax.servlet.http.WebConnection;
import org.apache.coyote.AbstractProcessorLight;
import org.apache.coyote.Request;
import org.apache.coyote.UpgradeToken;
import org.apache.tomcat.util.net.AbstractEndpoint.Handler.SocketState;
import org.apache.tomcat.util.net.SocketWrapperBase;
public abstract class UpgradeProcessorBase extends AbstractProcessorLight implements WebConnection {
protected static final int INFINITE_TIMEOUT = -1;
private final UpgradeToken upgradeToken;
public UpgradeProcessorBase(UpgradeToken upgradeToken) {
this.upgradeToken = upgradeToken;
}
// ------------------------------------------- Implemented Processor methods
@Override
public final boolean isUpgrade() {
return true;
}
@Override
public UpgradeToken getUpgradeToken() {
return upgradeToken;
}
@Override
public final void recycle() {
// Currently a NO-OP as upgrade processors are not recycled.
}
// ---------------------------- Processor methods that are NO-OP for upgrade
@Override
public final SocketState service(SocketWrapperBase<?> socketWrapper) throws IOException {
return null;
}
@Override
public final SocketState asyncPostProcess() {
return null;
}
@Override
public final boolean isAsync() {
return false;
}
@Override
public final Request getRequest() {
return null;
}
@Override
public ByteBuffer getLeftoverInput() {
return null;
}
@Override
public boolean checkAsyncTimeoutGeneration() {
return false;
}
// ----------------- Processor methods that are NO-OP by default for upgrade
@Override
public void timeoutAsync(long now) {
// NO-OP
}
}

View File

@@ -0,0 +1,139 @@
/*
* 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.upgrade;
import java.io.IOException;
import javax.servlet.ServletInputStream;
import javax.servlet.ServletOutputStream;
import org.apache.coyote.UpgradeToken;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
import org.apache.tomcat.util.net.AbstractEndpoint.Handler.SocketState;
import org.apache.tomcat.util.net.SSLSupport;
import org.apache.tomcat.util.net.SocketEvent;
import org.apache.tomcat.util.net.SocketWrapperBase;
import org.apache.tomcat.util.res.StringManager;
public class UpgradeProcessorExternal extends UpgradeProcessorBase {
private static final Log log = LogFactory.getLog(UpgradeProcessorExternal.class);
private static final StringManager sm = StringManager.getManager(UpgradeProcessorExternal.class);
private final UpgradeServletInputStream upgradeServletInputStream;
private final UpgradeServletOutputStream upgradeServletOutputStream;
public UpgradeProcessorExternal(SocketWrapperBase<?> wrapper,
UpgradeToken upgradeToken) {
super(upgradeToken);
this.upgradeServletInputStream = new UpgradeServletInputStream(this, wrapper);
this.upgradeServletOutputStream = new UpgradeServletOutputStream(this, wrapper);
/*
* Leave timeouts in the hands of the upgraded protocol.
*/
wrapper.setReadTimeout(INFINITE_TIMEOUT);
wrapper.setWriteTimeout(INFINITE_TIMEOUT);
}
@Override
protected Log getLog() {
return log;
}
// --------------------------------------------------- AutoCloseable methods
@Override
public void close() throws Exception {
upgradeServletInputStream.close();
upgradeServletOutputStream.close();
}
// --------------------------------------------------- WebConnection methods
@Override
public ServletInputStream getInputStream() throws IOException {
return upgradeServletInputStream;
}
@Override
public ServletOutputStream getOutputStream() throws IOException {
return upgradeServletOutputStream;
}
// ------------------------------------------- Implemented Processor methods
@Override
public final SocketState dispatch(SocketEvent status) {
if (status == SocketEvent.OPEN_READ) {
upgradeServletInputStream.onDataAvailable();
} else if (status == SocketEvent.OPEN_WRITE) {
upgradeServletOutputStream.onWritePossible();
} else if (status == SocketEvent.STOP) {
if (log.isDebugEnabled()) {
log.debug(sm.getString("upgradeProcessor.stop"));
}
try {
upgradeServletInputStream.close();
} catch (IOException ioe) {
log.debug(sm.getString("upgradeProcessor.isCloseFail", ioe));
}
try {
upgradeServletOutputStream.close();
} catch (IOException ioe) {
log.debug(sm.getString("upgradeProcessor.osCloseFail", ioe));
}
return SocketState.CLOSED;
} else {
// Unexpected state
if (log.isDebugEnabled()) {
log.debug(sm.getString("upgradeProcessor.unexpectedState"));
}
return SocketState.CLOSED;
}
if (upgradeServletInputStream.isClosed() &&
upgradeServletOutputStream.isClosed()) {
if (log.isDebugEnabled()) {
log.debug(sm.getString("upgradeProcessor.requiredClose",
Boolean.valueOf(upgradeServletInputStream.isClosed()),
Boolean.valueOf(upgradeServletOutputStream.isClosed())));
}
return SocketState.CLOSED;
}
return SocketState.UPGRADED;
}
// ----------------------------------------- Unimplemented Processor methods
@Override
public final void setSslSupport(SSLSupport sslSupport) {
// NO-OP
}
@Override
public void pause() {
// NOOP
}
}

View File

@@ -0,0 +1,101 @@
/*
* 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.upgrade;
import java.io.IOException;
import javax.servlet.ServletInputStream;
import javax.servlet.ServletOutputStream;
import org.apache.coyote.UpgradeToken;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
import org.apache.tomcat.util.net.AbstractEndpoint.Handler.SocketState;
import org.apache.tomcat.util.net.SSLSupport;
import org.apache.tomcat.util.net.SocketEvent;
import org.apache.tomcat.util.net.SocketWrapperBase;
public class UpgradeProcessorInternal extends UpgradeProcessorBase {
private static final Log log = LogFactory.getLog(UpgradeProcessorInternal.class);
private final InternalHttpUpgradeHandler internalHttpUpgradeHandler;
public UpgradeProcessorInternal(SocketWrapperBase<?> wrapper,
UpgradeToken upgradeToken) {
super(upgradeToken);
this.internalHttpUpgradeHandler = (InternalHttpUpgradeHandler) upgradeToken.getHttpUpgradeHandler();
/*
* Leave timeouts in the hands of the upgraded protocol.
*/
wrapper.setReadTimeout(INFINITE_TIMEOUT);
wrapper.setWriteTimeout(INFINITE_TIMEOUT);
internalHttpUpgradeHandler.setSocketWrapper(wrapper);
}
@Override
public SocketState dispatch(SocketEvent status) {
return internalHttpUpgradeHandler.upgradeDispatch(status);
}
@Override
public final void setSslSupport(SSLSupport sslSupport) {
internalHttpUpgradeHandler.setSslSupport(sslSupport);
}
@Override
public void pause() {
internalHttpUpgradeHandler.pause();
}
@Override
protected Log getLog() {
return log;
}
@Override
public void timeoutAsync(long now) {
internalHttpUpgradeHandler.timeoutAsync(now);
}
// --------------------------------------------------- AutoCloseable methods
@Override
public void close() throws Exception {
internalHttpUpgradeHandler.destroy();
}
// --------------------------------------------------- WebConnection methods
@Override
public ServletInputStream getInputStream() throws IOException {
return null;
}
@Override
public ServletOutputStream getOutputStream() throws IOException {
return null;
}
}

View File

@@ -0,0 +1,258 @@
/*
* 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.upgrade;
import java.io.IOException;
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import org.apache.coyote.ContainerThreadMarker;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
import org.apache.tomcat.util.ExceptionUtils;
import org.apache.tomcat.util.net.DispatchType;
import org.apache.tomcat.util.net.SocketWrapperBase;
import org.apache.tomcat.util.res.StringManager;
public class UpgradeServletInputStream extends ServletInputStream {
private static final Log log = LogFactory.getLog(UpgradeServletInputStream.class);
private static final StringManager sm =
StringManager.getManager(UpgradeServletInputStream.class);
private final UpgradeProcessorBase processor;
private final SocketWrapperBase<?> socketWrapper;
private volatile boolean closed = false;
private volatile boolean eof = false;
// Start in blocking-mode
private volatile Boolean ready = Boolean.TRUE;
private volatile ReadListener listener = null;
public UpgradeServletInputStream(UpgradeProcessorBase processor,
SocketWrapperBase<?> socketWrapper) {
this.processor = processor;
this.socketWrapper = socketWrapper;
}
@Override
public final boolean isFinished() {
if (listener == null) {
throw new IllegalStateException(
sm.getString("upgrade.sis.isFinished.ise"));
}
return eof;
}
@Override
public final boolean isReady() {
if (listener == null) {
throw new IllegalStateException(
sm.getString("upgrade.sis.isReady.ise"));
}
if (eof || closed) {
return false;
}
// If we already know the current state, return it.
if (ready != null) {
return ready.booleanValue();
}
try {
ready = Boolean.valueOf(socketWrapper.isReadyForRead());
} catch (IOException e) {
onError(e);
}
return ready.booleanValue();
}
@Override
public final void setReadListener(ReadListener listener) {
if (listener == null) {
throw new IllegalArgumentException(
sm.getString("upgrade.sis.readListener.null"));
}
if (this.listener != null) {
throw new IllegalArgumentException(
sm.getString("upgrade.sis.readListener.set"));
}
if (closed) {
throw new IllegalStateException(sm.getString("upgrade.sis.read.closed"));
}
this.listener = listener;
// Container is responsible for first call to onDataAvailable().
if (ContainerThreadMarker.isContainerThread()) {
processor.addDispatch(DispatchType.NON_BLOCKING_READ);
} else {
socketWrapper.registerReadInterest();
}
// Switching to non-blocking. Don't know if data is available.
ready = null;
}
@Override
public final int read() throws IOException {
preReadChecks();
return readInternal();
}
@Override
public final int readLine(byte[] b, int off, int len) throws IOException {
preReadChecks();
if (len <= 0) {
return 0;
}
int count = 0, c;
while ((c = readInternal()) != -1) {
b[off++] = (byte) c;
count++;
if (c == '\n' || count == len) {
break;
}
}
return count > 0 ? count : -1;
}
@Override
public final int read(byte[] b, int off, int len) throws IOException {
preReadChecks();
try {
int result = socketWrapper.read(listener == null, b, off, len);
if (result == -1) {
eof = true;
}
return result;
} catch (IOException ioe) {
close();
throw ioe;
}
}
@Override
public void close() throws IOException {
eof = true;
closed = true;
}
private void preReadChecks() {
if (listener != null && (ready == null || !ready.booleanValue())) {
throw new IllegalStateException(sm.getString("upgrade.sis.read.ise"));
}
if (closed) {
throw new IllegalStateException(sm.getString("upgrade.sis.read.closed"));
}
// No longer know if data is available
ready = null;
}
private int readInternal() throws IOException {
// Single byte reads for non-blocking need special handling so all
// single byte reads run through this method.
byte[] b = new byte[1];
int result;
try {
result = socketWrapper.read(listener == null, b, 0, 1);
} catch (IOException ioe) {
close();
throw ioe;
}
if (result == 0) {
return -1;
} else if (result == -1) {
eof = true;
return -1;
} else {
return b[0] & 0xFF;
}
}
final void onDataAvailable() {
try {
if (listener == null || !socketWrapper.isReadyForRead()) {
return;
}
} catch (IOException e) {
onError(e);
}
ready = Boolean.TRUE;
ClassLoader oldCL = processor.getUpgradeToken().getContextBind().bind(false, null);
try {
if (!eof) {
listener.onDataAvailable();
}
if (eof) {
listener.onAllDataRead();
}
} catch (Throwable t) {
ExceptionUtils.handleThrowable(t);
onError(t);
} finally {
processor.getUpgradeToken().getContextBind().unbind(false, oldCL);
}
}
private final void onError(Throwable t) {
if (listener == null) {
return;
}
ClassLoader oldCL = processor.getUpgradeToken().getContextBind().bind(false, null);
try {
listener.onError(t);
} catch (Throwable t2) {
ExceptionUtils.handleThrowable(t2);
log.warn(sm.getString("upgrade.sis.onErrorFail"), t2);
} finally {
processor.getUpgradeToken().getContextBind().unbind(false, oldCL);
}
try {
close();
} catch (IOException ioe) {
if (log.isDebugEnabled()) {
log.debug(sm.getString("upgrade.sis.errorCloseFail"), ioe);
}
}
ready = Boolean.FALSE;
}
final boolean isClosed() {
return closed;
}
}

View File

@@ -0,0 +1,282 @@
/*
* 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.upgrade;
import java.io.IOException;
import javax.servlet.ServletOutputStream;
import javax.servlet.WriteListener;
import org.apache.coyote.ContainerThreadMarker;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
import org.apache.tomcat.util.ExceptionUtils;
import org.apache.tomcat.util.net.DispatchType;
import org.apache.tomcat.util.net.SocketWrapperBase;
import org.apache.tomcat.util.res.StringManager;
public class UpgradeServletOutputStream extends ServletOutputStream {
private static final Log log = LogFactory.getLog(UpgradeServletOutputStream.class);
private static final StringManager sm =
StringManager.getManager(UpgradeServletOutputStream.class);
private final UpgradeProcessorBase processor;
private final SocketWrapperBase<?> socketWrapper;
// Used to ensure that isReady() and onWritePossible() have a consistent
// view of buffer and registered.
private final Object registeredLock = new Object();
// Used to ensure that only one thread writes to the socket at a time and
// that buffer is consistently updated with any unwritten data after the
// write. Note it is not necessary to hold this lock when checking if buffer
// contains data but, depending on how the result is used, some form of
// synchronization may be required (see fireListenerLock for an example).
private final Object writeLock = new Object();
private volatile boolean flushing = false;
private volatile boolean closed = false;
// Start in blocking-mode
private volatile WriteListener listener = null;
// Guarded by registeredLock
private boolean registered = false;
public UpgradeServletOutputStream(UpgradeProcessorBase processor,
SocketWrapperBase<?> socketWrapper) {
this.processor = processor;
this.socketWrapper = socketWrapper;
}
@Override
public final boolean isReady() {
if (listener == null) {
throw new IllegalStateException(
sm.getString("upgrade.sos.canWrite.ise"));
}
if (closed) {
return false;
}
// Make sure isReady() and onWritePossible() have a consistent view of
// fireListener when determining if the listener should fire
synchronized (registeredLock) {
if (flushing) {
// Since flushing is true the socket must already be registered
// for write and multiple registrations will cause problems.
registered = true;
return false;
} else if (registered){
// The socket is already registered for write and multiple
// registrations will cause problems.
return false;
} else {
boolean result = socketWrapper.isReadyForWrite();
registered = !result;
return result;
}
}
}
@Override
public final void setWriteListener(WriteListener listener) {
if (listener == null) {
throw new IllegalArgumentException(
sm.getString("upgrade.sos.writeListener.null"));
}
if (this.listener != null) {
throw new IllegalArgumentException(
sm.getString("upgrade.sos.writeListener.set"));
}
if (closed) {
throw new IllegalStateException(sm.getString("upgrade.sos.write.closed"));
}
this.listener = listener;
// Container is responsible for first call to onWritePossible().
synchronized (registeredLock) {
registered = true;
// Container is responsible for first call to onDataAvailable().
if (ContainerThreadMarker.isContainerThread()) {
processor.addDispatch(DispatchType.NON_BLOCKING_WRITE);
} else {
socketWrapper.registerWriteInterest();
}
}
}
final boolean isClosed() {
return closed;
}
@Override
public void write(int b) throws IOException {
synchronized (writeLock) {
preWriteChecks();
writeInternal(new byte[] { (byte) b }, 0, 1);
}
}
@Override
public void write(byte[] b, int off, int len) throws IOException {
synchronized (writeLock) {
preWriteChecks();
writeInternal(b, off, len);
}
}
@Override
public void flush() throws IOException {
preWriteChecks();
flushInternal(listener == null, true);
}
private void flushInternal(boolean block, boolean updateFlushing) throws IOException {
try {
synchronized (writeLock) {
if (updateFlushing) {
flushing = socketWrapper.flush(block);
if (flushing) {
socketWrapper.registerWriteInterest();
}
} else {
socketWrapper.flush(block);
}
}
} catch (Throwable t) {
ExceptionUtils.handleThrowable(t);
onError(t);
if (t instanceof IOException) {
throw (IOException) t;
} else {
throw new IOException(t);
}
}
}
@Override
public void close() throws IOException {
if (closed) {
return;
}
closed = true;
flushInternal((listener == null), false);
}
private void preWriteChecks() {
if (listener != null && !socketWrapper.canWrite()) {
throw new IllegalStateException(sm.getString("upgrade.sos.write.ise"));
}
if (closed) {
throw new IllegalStateException(sm.getString("upgrade.sos.write.closed"));
}
}
/**
* Must hold writeLock to call this method.
*/
private void writeInternal(byte[] b, int off, int len) throws IOException {
if (listener == null) {
// Simple case - blocking IO
socketWrapper.write(true, b, off, len);
} else {
socketWrapper.write(false, b, off, len);
}
}
final void onWritePossible() {
try {
if (flushing) {
flushInternal(false, true);
if (flushing) {
return;
}
} else {
// This may fill the write buffer in which case the
// isReadyForWrite() call below will re-register the socket for
// write
flushInternal(false, false);
}
} catch (IOException ioe) {
onError(ioe);
return;
}
// Make sure isReady() and onWritePossible() have a consistent view
// of buffer and fireListener when determining if the listener
// should fire
boolean fire = false;
synchronized (registeredLock) {
if (socketWrapper.isReadyForWrite()) {
registered = false;
fire = true;
} else {
registered = true;
}
}
if (fire) {
ClassLoader oldCL = processor.getUpgradeToken().getContextBind().bind(false, null);
try {
listener.onWritePossible();
} catch (Throwable t) {
ExceptionUtils.handleThrowable(t);
onError(t);
} finally {
processor.getUpgradeToken().getContextBind().unbind(false, oldCL);
}
}
}
private final void onError(Throwable t) {
if (listener == null) {
return;
}
ClassLoader oldCL = processor.getUpgradeToken().getContextBind().bind(false, null);
try {
listener.onError(t);
} catch (Throwable t2) {
ExceptionUtils.handleThrowable(t2);
log.warn(sm.getString("upgrade.sos.onErrorFail"), t2);
} finally {
processor.getUpgradeToken().getContextBind().unbind(false, oldCL);
}
try {
close();
} catch (IOException ioe) {
if (log.isDebugEnabled()) {
log.debug(sm.getString("upgrade.sos.errorCloseFail"), ioe);
}
}
}
}