/* * 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;
/** * This is a low-level, efficient representation of a server request. Most fields are GC-free, expensive operations are * delayed until the user code needs the information. Processing is delegated to modules, using a hook mechanism. This * class is not intended for user code - it is used internally by tomcat for processing the request in the most * efficient way. Users ( servlets ) can access the information using a facade, which provides the high-level view of * the request. Tomcat defines a number of attributes: * <ul> * <li>"org.apache.tomcat.request" - allows access to the low-level request object in trusted applications * </ul> * * @author James Duncan Davidson [duncan@eng.sun.com] * @author James Todd [gonzo@eng.sun.com] * @author Jason Hunter [jch@eng.sun.com] * @author Harish Prabandham * @author Alex Cruikshank [alex@epitonic.com] * @author Hans Bergsten [hans@gefionsoftware.com] * @author Costin Manolache * @author Remy Maucherat
*/ publicfinalclass Request {
privatestaticfinal StringManager sm = StringManager.getManager(Request.class);
// Expected maximum typical number of cookies per request. privatestaticfinalint INITIAL_COOKIE_SIZE = 4;
/* * At 100,000 requests a second there are enough IDs here for ~3,000,000 years before it overflows (and then we have * another 3,000,000 years before it gets back to zero). * * Local testing shows that 5, 10, 50, 500 or 1000 threads can obtain 60,000,000+ IDs a second from a single * AtomicLong. That is about about 17ns per request. It does not appear that the introduction of this counter will * cause a bottleneck for request processing.
*/ privatestaticfinal AtomicLong requestIdGenerator = new AtomicLong(0);
/** * HTTP specific fields. (remove them ?)
*/ privatelong contentLength = -1; private MessageBytes contentTypeMB = null; private Charset charset = null; // Retain the original, user specified character encoding so it can be // returned even if it is invalid private String characterEncoding = null;
/** * Is there an expectation ?
*/ privateboolean expectation = false;
privatefinal ServerCookies serverCookies = new ServerCookies(INITIAL_COOKIE_SIZE); privatefinal Parameters parameters = new Parameters();
privatelong bytesRead = 0; // Time of the request - useful to avoid repeated calls to System.currentTime privatelong startTimeNanos = -1; privatelong threadId = 0; privateint available = 0;
privatefinal RequestInfo reqProcessorMX = new RequestInfo(this);
/* * State for non-blocking output is maintained here as it is the one point easily reachable from the * CoyoteInputStream and the CoyoteAdapter which both need access to state.
*/ volatile ReadListener listener; // Ensures listener is only fired after a call is isReady() privateboolean fireListener = false; // Tracks read registration to prevent duplicate registrations privateboolean registeredForRead = false; // Lock used to manage concurrent access to above flags privatefinal Object nonBlockingStateLock = new Object();
public ReadListener getReadListener() { return listener;
}
publicvoid setReadListener(ReadListener listener) { if (listener == null) { thrownew NullPointerException(sm.getString("request.nullReadListener"));
} if (getReadListener() != null) { thrownew IllegalStateException(sm.getString("request.readListenerSet"));
} // Note: This class is not used for HTTP upgrade so only need to test // for async
AtomicBoolean result = new AtomicBoolean(false);
action(ActionCode.ASYNC_IS_ASYNC, result); if (!result.get()) { thrownew IllegalStateException(sm.getString("request.notAsync"));
}
this.listener = listener;
// The container is responsible for the first call to // listener.onDataAvailable(). If isReady() returns true, the container // needs to call listener.onDataAvailable() from a new thread. If // isReady() returns false, the socket will be registered for read and // the container will call listener.onDataAvailable() once data arrives. // Must call isFinished() first as a call to isReady() if the request // has been finished will register the socket for read interest and that // is not required. if (!isFinished() && isReady()) { synchronized (nonBlockingStateLock) { // Ensure we don't get multiple read registrations
registeredForRead = true; // Need to set the fireListener flag otherwise when the // container tries to trigger onDataAvailable, nothing will // happen
fireListener = true;
}
action(ActionCode.DISPATCH_READ, null); if (!isRequestThread()) { // Not on a container thread so need to execute the dispatch
action(ActionCode.DISPATCH_EXECUTE, null);
}
}
}
publicboolean isReady() { // Assume read is not possible boolean ready = false; synchronized (nonBlockingStateLock) { if (registeredForRead) {
fireListener = true; returnfalse;
}
ready = checkRegisterForRead();
fireListener = !ready;
} return ready;
}
public MimeHeaders getMimeHeaders() { return headers;
}
publicboolean isTrailerFieldsReady() {
AtomicBoolean result = new AtomicBoolean(false);
action(ActionCode.IS_TRAILER_FIELDS_READY, result); return result.get();
}
public Map<String, String> getTrailerFields() { return trailerFields;
}
public UDecoder getURLDecoder() { return urlDecoder;
}
// -------------------- Request data --------------------
public MessageBytes scheme() { return schemeMB;
}
public MessageBytes method() { return methodMB;
}
public MessageBytes requestURI() { return uriMB;
}
public MessageBytes decodedURI() { return decodedUriMB;
}
public MessageBytes queryString() { return queryMB;
}
public MessageBytes protocol() { return protoMB;
}
/** * Get the "virtual host", derived from the Host: header associated with this request. * * @return The buffer holding the server name, if any. Use isNull() to check if there is no value set.
*/ public MessageBytes serverName() { return serverNameMB;
}
/** * Get the character encoding used for this request. * * @return The value set via {@link #setCharset(Charset)} or if no call has been made to that method try to obtain * if from the content type.
*/ public String getCharacterEncoding() { if (characterEncoding == null) {
characterEncoding = getCharsetFromContentType(getContentType());
}
return characterEncoding;
}
/** * Get the character encoding used for this request. * * @return The value set via {@link #setCharset(Charset)} or if no call has been made to that method try to obtain * if from the content type. * * @throws UnsupportedEncodingException If the user agent has specified an invalid character encoding
*/ public Charset getCharset() throws UnsupportedEncodingException { if (charset == null) {
getCharacterEncoding(); if (characterEncoding != null) {
charset = B2CConverter.getCharset(characterEncoding);
}
}
/** * Read data from the input buffer and put it into ApplicationBufferHandler. The buffer is owned by the protocol * implementation - it will be reused on the next read. The Adapter must either process the data in place or copy it * to a separate buffer if it needs to hold it. In most cases this is done during byte->char conversions or via * InputStream. Unlike InputStream, this interface allows the app to process data in place, without copy. * * @param handler The destination to which to copy the data * * @return The number of bytes copied * * @throws IOException If an I/O error occurs during the copy
*/ publicint doRead(ApplicationBufferHandler handler) throws IOException { if (getBytesRead() == 0 && !response.isCommitted()) {
action(ActionCode.ACK, ContinueResponseTiming.ON_REQUEST_BODY_READ);
}
int n = inputBuffer.doRead(handler); if (n > 0) {
bytesRead += n;
} return n;
}
/** * Set the error Exception that occurred during the writing of the response processing. * * @param ex The exception that occurred
*/ publicvoid setErrorException(Exception ex) {
errorException = ex;
}
/** * Get the Exception that occurred during the writing of the response. * * @return The exception that occurred
*/ public Exception getErrorException() { return errorException;
}
/** * Used to store private data. Thread data could be used instead - but if you have the req, getting/setting a note * is just an array access, may be faster than ThreadLocal for very frequent operations. Example use: Catalina * CoyoteAdapter: ADAPTER_NOTES = 1 - stores the HttpServletRequest object ( req/res) To avoid conflicts, note in * the range 0 - 8 are reserved for the servlet container ( catalina connector, etc ), and values in 9 - 16 for * connector use. 17-31 range is not allocated or used. * * @param pos Index to use to store the note * @param value The value to store at that index
*/ publicvoid setNote(int pos, Object value) {
notes[pos] = value;
}
public Object getNote(int pos) { return notes[pos];
}
// There may be multiple calls to recycle but only the first should // trigger a change in the request ID until a new request has been // started. Use startTimeNanos to detect when a request has started so a // subsequent call to recycle() will trigger a change in the request ID. if (startTimeNanos != -1) {
requestId = Long.toHexString(requestIdGenerator.getAndIncrement());
}
/** * Parse the character encoding from the specified content type header. If the content type is null, or there is no * explicit character encoding, <code>null</code> is returned. * * @param contentType a content type header
*/ privatestatic String getCharsetFromContentType(String contentType) {
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.