/** *HTTPspecificfields.
*/
String contentType = null;
String contentLanguage = null;
Charset charset = null; // Retain the original name used to set the charset so exactly that name is // used in the ContentType header. Some (arguably non-specification // compliant) user agents are very particular
String characterEncoding = null; long contentLength = -1; private Locale locale = DEFAULT_LOCALE;
// General information privatelong contentWritten = 0; privatelong commitTimeNanos = -1;
publicvoid addHeader(String name, String value, Charset charset) { char cc = name.charAt(0); if (cc == 'C' || cc == 'c') { if (checkSpecialHeader(name, value)) { return;
}
}
MessageBytes mb = headers.addValue(name); if (charset != null) {
mb.setCharset(charset);
}
mb.setString(value);
}
publicvoid setTrailerFields(Supplier<Map<String, String>> supplier) {
AtomicBoolean trailerFieldsSupported = new AtomicBoolean(false);
action(ActionCode.IS_TRAILER_FIELDS_SUPPORTED, trailerFieldsSupported); if (!trailerFieldsSupported.get()) { thrownew IllegalStateException(sm.getString("response.noTrailers.notSupported"));
}
this.trailerFieldsSupplier = supplier;
}
public Supplier<Map<String, String>> getTrailerFields() { return trailerFieldsSupplier;
}
/** *Setinternalfieldsforspecialheadernames.Calledfromset/addHeader.Returntrueiftheheaderisspecial,no *needtosettheheader.
*/ privateboolean checkSpecialHeader(String name, String value) { // XXX Eliminate redundant fields !!! // ( both header and in special fields ) if (name.equalsIgnoreCase("Content-Type")) {
setContentType(value); returntrue;
} if (name.equalsIgnoreCase("Content-Length")) { try { long cL = Long.parseLong(value);
setContentLength(cL); returntrue;
} catch (NumberFormatException ex) { // Do nothing - the spec doesn't have any "throws" // and the user might know what they're doing returnfalse;
}
} returnfalse;
}
if (type == null) { this.contentType = null; return;
}
MediaType m = null; try {
m = MediaType.parseMediaType(new StringReader(type));
} catch (IOException e) { // Ignore - null test below handles this
} if (m == null) { // Invalid - Assume no charset and just pass through whatever // the user provided. this.contentType = type; return;
}
this.contentType = m.toStringNoCharset();
String charsetValue = m.getCharset();
if (charsetValue == null) { // No charset and we know value is valid as parser was successful // Pass-through user provided value in case user-agent is buggy and // requires specific format this.contentType = type;
} else { // There is a charset so have to rebuild content-type without it this.contentType = m.toStringNoCharset();
charsetValue = charsetValue.trim(); if (charsetValue.length() > 0) { try {
charset = B2CConverter.getCharset(charsetValue);
} catch (UnsupportedEncodingException e) {
log.warn(sm.getString("response.encoding.invalid", charsetValue), e);
}
}
}
}
/* *Statefornon-blockingoutputismaintainedhereasitistheonepointeasilyreachablefromthe *CoyoteOutputStreamandtheProcessorwhichbothneedaccesstostate.
*/ volatile WriteListener listener; // Ensures listener is only fired after a call is isReady() privateboolean fireListener = false; // Tracks write registration to prevent duplicate registrations privateboolean registeredForWrite = false; // Lock used to manage concurrent access to above flags privatefinal Object nonBlockingStateLock = new Object();
public WriteListener getWriteListener() { return listener;
}
publicvoid setWriteListener(WriteListener listener) { if (listener == null) { thrownew NullPointerException(sm.getString("response.nullWriteListener"));
} if (getWriteListener() != null) { thrownew IllegalStateException(sm.getString("response.writeListenerSet"));
} // 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("response.notAsync"));
}
this.listener = listener;
// The container is responsible for the first call to // listener.onWritePossible(). If isReady() returns true, the container // needs to call listener.onWritePossible() from a new thread. If // isReady() returns false, the socket will be registered for write and // the container will call listener.onWritePossible() once data can be // written. if (isReady()) { synchronized (nonBlockingStateLock) { // Ensure we don't get multiple write registrations if // ServletOutputStream.isReady() returns false during a call to // onDataAvailable()
registeredForWrite = true; // Need to set the fireListener flag otherwise when the // container tries to trigger onWritePossible, nothing will // happen
fireListener = true;
}
action(ActionCode.DISPATCH_WRITE, null); if (!req.isRequestThread()) { // Not on a container thread so need to execute the dispatch
action(ActionCode.DISPATCH_EXECUTE, null);
}
}
}
publicboolean isReady() { if (listener == null) { if (log.isDebugEnabled()) {
log.debug(sm.getString("response.notNonBlocking"));
} returnfalse;
} // Assume write is not possible boolean ready = false; synchronized (nonBlockingStateLock) { if (registeredForWrite) {
fireListener = true; returnfalse;
}
ready = checkRegisterForWrite();
fireListener = !ready;
} return ready;
}
publicvoid onWritePossible() throws IOException { // Any buffered data left over from a previous non-blocking write is // written in the Processor so if this point is reached the app is able // to write data. boolean fire = false; synchronized (nonBlockingStateLock) {
registeredForWrite = false; if (fireListener) {
fireListener = false;
fire = true;
}
} if (fire) {
listener.onWritePossible();
}
}
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.17 Sekunden
(vorverarbeitet am 2026-09-29)
¤
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 und die Messung sind noch experimentell.