📄 internalaprinputbuffer.java
字号:
/*
* 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.io.EOFException;
import java.net.SocketTimeoutException;
import java.nio.ByteBuffer;
import org.apache.tomcat.jni.Socket;
import org.apache.tomcat.jni.Status;
import org.apache.tomcat.util.buf.ByteChunk;
import org.apache.tomcat.util.buf.MessageBytes;
import org.apache.tomcat.util.http.MimeHeaders;
import org.apache.tomcat.util.res.StringManager;
import org.apache.coyote.InputBuffer;
import org.apache.coyote.Request;
/**
* Implementation of InputBuffer which provides HTTP request header parsing as
* well as transfer decoding.
*
* @author <a href="mailto:remm@apache.org">Remy Maucherat</a>
*/
public class InternalAprInputBuffer implements InputBuffer {
// -------------------------------------------------------------- Constants
// ----------------------------------------------------------- Constructors
/**
* Alternate constructor.
*/
public InternalAprInputBuffer(Request request, int headerBufferSize,
long readTimeout) {
this.request = request;
headers = request.getMimeHeaders();
buf = new byte[headerBufferSize];
if (headerBufferSize < (8 * 1024)) {
bbuf = ByteBuffer.allocateDirect(6 * 1500);
} else {
bbuf = ByteBuffer.allocateDirect((headerBufferSize / 1500 + 1) * 1500);
}
inputStreamInputBuffer = new SocketInputBuffer();
filterLibrary = new InputFilter[0];
activeFilters = new InputFilter[0];
lastActiveFilter = -1;
parsingHeader = true;
swallowInput = true;
if (readTimeout < 0) {
this.readTimeout = -1;
} else {
this.readTimeout = readTimeout * 1000;
}
}
// -------------------------------------------------------------- Variables
/**
* The string manager for this package.
*/
protected static StringManager sm =
StringManager.getManager(Constants.Package);
// ----------------------------------------------------- Instance Variables
/**
* Associated Coyote request.
*/
protected Request request;
/**
* Headers of the associated request.
*/
protected MimeHeaders headers;
/**
* State.
*/
protected boolean parsingHeader;
/**
* Swallow input ? (in the case of an expectation)
*/
protected boolean swallowInput;
/**
* Pointer to the current read buffer.
*/
protected byte[] buf;
/**
* Last valid byte.
*/
protected int lastValid;
/**
* Position in the buffer.
*/
protected int pos;
/**
* Pos of the end of the header in the buffer, which is also the
* start of the body.
*/
protected int end;
/**
* Direct byte buffer used to perform actual reading.
*/
protected ByteBuffer bbuf;
/**
* Underlying socket.
*/
protected long socket;
/**
* Underlying input buffer.
*/
protected InputBuffer inputStreamInputBuffer;
/**
* Filter library.
* Note: Filter[0] is always the "chunked" filter.
*/
protected InputFilter[] filterLibrary;
/**
* Active filters (in order).
*/
protected InputFilter[] activeFilters;
/**
* Index of the last active filter.
*/
protected int lastActiveFilter;
/**
* The socket timeout used when reading the first block of the request
* header.
*/
protected long readTimeout;
// ------------------------------------------------------------- Properties
/**
* Set the underlying socket.
*/
public void setSocket(long socket) {
this.socket = socket;
Socket.setrbb(this.socket, bbuf);
}
/**
* Get the underlying socket input stream.
*/
public long getSocket() {
return socket;
}
/**
* Add an input filter to the filter library.
*/
public void addFilter(InputFilter filter) {
InputFilter[] newFilterLibrary =
new InputFilter[filterLibrary.length + 1];
for (int i = 0; i < filterLibrary.length; i++) {
newFilterLibrary[i] = filterLibrary[i];
}
newFilterLibrary[filterLibrary.length] = filter;
filterLibrary = newFilterLibrary;
activeFilters = new InputFilter[filterLibrary.length];
}
/**
* Get filters.
*/
public InputFilter[] getFilters() {
return filterLibrary;
}
/**
* Clear filters.
*/
public void clearFilters() {
filterLibrary = new InputFilter[0];
lastActiveFilter = -1;
}
/**
* Add an input filter to the filter library.
*/
public void addActiveFilter(InputFilter filter) {
if (lastActiveFilter == -1) {
filter.setBuffer(inputStreamInputBuffer);
} else {
for (int i = 0; i <= lastActiveFilter; i++) {
if (activeFilters[i] == filter)
return;
}
filter.setBuffer(activeFilters[lastActiveFilter]);
}
activeFilters[++lastActiveFilter] = filter;
filter.setRequest(request);
}
/**
* Set the swallow input flag.
*/
public void setSwallowInput(boolean swallowInput) {
this.swallowInput = swallowInput;
}
// --------------------------------------------------------- Public Methods
/**
* Recycle the input buffer. This should be called when closing the
* connection.
*/
public void recycle() {
// Recycle Request object
request.recycle();
socket = 0;
lastValid = 0;
pos = 0;
lastActiveFilter = -1;
parsingHeader = true;
swallowInput = true;
}
/**
* 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 Request object
request.recycle();
// Copy leftover bytes to the beginning of the buffer
if (lastValid - pos > 0) {
int npos = 0;
int opos = pos;
while (lastValid - opos > opos - npos) {
System.arraycopy(buf, opos, buf, npos, opos - npos);
npos += pos;
opos += pos;
}
System.arraycopy(buf, opos, buf, npos, lastValid - opos);
}
// Recycle filters
for (int i = 0; i <= lastActiveFilter; i++) {
activeFilters[i].recycle();
}
// Reset pointers
lastValid = lastValid - pos;
pos = 0;
lastActiveFilter = -1;
parsingHeader = true;
swallowInput = true;
}
/**
* End request (consumes leftover bytes).
*
* @throws IOException an undelying I/O error occured
*/
public void endRequest()
throws IOException {
if (swallowInput && (lastActiveFilter != -1)) {
int extraBytes = (int) activeFilters[lastActiveFilter].end();
pos = pos - extraBytes;
}
}
/**
* Read the request line. This function is meant to be used during the
* HTTP request header parsing. Do NOT attempt to read the request body
* using it.
*
* @throws IOException If an exception occurs during the underlying socket
* read operations, or if the given buffer is not big enough to accomodate
* the whole line.
* @return true if data is properly fed; false if no data is available
* immediately and thread should be freed
*/
public boolean parseRequestLine(boolean useAvailableData)
throws IOException {
int start = 0;
//
// Skipping blank lines
//
byte chr = 0;
do {
// Read new bytes if needed
if (pos >= lastValid) {
if (useAvailableData) {
return false;
}
if (readTimeout == -1) {
if (!fill())
throw new EOFException(sm.getString("iib.eof.error"));
} else {
// Do a simple read with a short timeout
bbuf.clear();
int nRead = Socket.recvbbt
(socket, 0, buf.length - lastValid, readTimeout);
if (nRead > 0) {
bbuf.limit(nRead);
bbuf.get(buf, pos, nRead);
lastValid = pos + nRead;
} else {
if ((-nRead) == Status.ETIMEDOUT || (-nRead) == Status.TIMEUP) {
return false;
} else {
throw new IOException(sm.getString("iib.failedread"));
}
}
}
}
chr = buf[pos++];
} while ((chr == Constants.CR) || (chr == Constants.LF));
pos--;
// Mark the current buffer position
start = pos;
if (pos >= lastValid) {
if (useAvailableData) {
return false;
}
if (readTimeout == -1) {
if (!fill())
throw new EOFException(sm.getString("iib.eof.error"));
} else {
// Do a simple read with a short timeout
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -