< prev index next >
src/java.base/share/classes/sun/security/ssl/MaxFragExtension.java
Print this page
*** 1,7 ****
/*
! * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
--- 1,7 ----
/*
! * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
*** 24,139 ****
*/
package sun.security.ssl;
import java.io.IOException;
import javax.net.ssl.SSLProtocolException;
! /*
! * [RFC6066] TLS specifies a fixed maximum plaintext fragment length of
! * 2^14 bytes. It may be desirable for constrained clients to negotiate
! * a smaller maximum fragment length due to memory limitations or bandwidth
! * limitations.
! *
! * In order to negotiate smaller maximum fragment lengths, clients MAY
! * include an extension of type "max_fragment_length" in the (extended)
! * client hello. The "extension_data" field of this extension SHALL
! * contain:
! *
! * enum{
! * 2^9(1), 2^10(2), 2^11(3), 2^12(4), (255)
! * } MaxFragmentLength;
! *
! * whose value is the desired maximum fragment length.
*/
! final class MaxFragmentLengthExtension extends HelloExtension {
! private static final int MAX_FRAGMENT_LENGTH_512 = 1; // 2^9
! private static final int MAX_FRAGMENT_LENGTH_1024 = 2; // 2^10
! private static final int MAX_FRAGMENT_LENGTH_2048 = 3; // 2^11
! private static final int MAX_FRAGMENT_LENGTH_4096 = 4; // 2^12
! final int maxFragmentLength;
! MaxFragmentLengthExtension(int fragmentSize) {
! super(ExtensionType.EXT_MAX_FRAGMENT_LENGTH);
! if (fragmentSize < 1024) {
! maxFragmentLength = MAX_FRAGMENT_LENGTH_512;
} else if (fragmentSize < 2048) {
! maxFragmentLength = MAX_FRAGMENT_LENGTH_1024;
} else if (fragmentSize < 4096) {
! maxFragmentLength = MAX_FRAGMENT_LENGTH_2048;
} else {
! maxFragmentLength = MAX_FRAGMENT_LENGTH_4096;
}
}
! MaxFragmentLengthExtension(HandshakeInStream s, int len)
! throws IOException {
! super(ExtensionType.EXT_MAX_FRAGMENT_LENGTH);
! // check the extension length
! if (len != 1) {
! throw new SSLProtocolException("Invalid " + type + " extension");
}
! maxFragmentLength = s.getInt8();
! if ((maxFragmentLength > 4) || (maxFragmentLength < 1)) {
! throw new SSLProtocolException("Invalid " + type + " extension");
}
}
! // Length of the encoded extension, including the type and length fields
@Override
! int length() {
! return 5; // 4: extension type and length fields
! // 1: MaxFragmentLength field
}
@Override
! void send(HandshakeOutStream s) throws IOException {
! s.putInt16(type.id);
! s.putInt16(1);
! s.putInt8(maxFragmentLength);
}
! int getMaxFragLen() {
! switch (maxFragmentLength) {
! case MAX_FRAGMENT_LENGTH_512:
! return 512;
! case MAX_FRAGMENT_LENGTH_1024:
! return 1024;
! case MAX_FRAGMENT_LENGTH_2048:
! return 2048;
! case MAX_FRAGMENT_LENGTH_4096:
! return 4096;
}
! // unlikely to happen
! return -1;
}
! static boolean needFragLenNego(int fragmentSize) {
! return (fragmentSize > 0) && (fragmentSize <= 4096);
}
! static int getValidMaxFragLen(int fragmentSize) {
! if (fragmentSize < 1024) {
! return 512;
! } else if (fragmentSize < 2048) {
! return 1024;
! } else if (fragmentSize < 4096) {
! return 2048;
! } else if (fragmentSize == 4096) {
! return 4096;
! } else {
! return 16384;
}
}
@Override
! public String toString() {
! return "Extension " + type + ", max_fragment_length: " +
! "(2^" + (maxFragmentLength + 8) + ")";
}
}
--- 24,620 ----
*/
package sun.security.ssl;
import java.io.IOException;
+ import java.nio.ByteBuffer;
import javax.net.ssl.SSLProtocolException;
+ import static sun.security.ssl.SSLExtension.CH_MAX_FRAGMENT_LENGTH;
+ import static sun.security.ssl.SSLExtension.EE_MAX_FRAGMENT_LENGTH;
+ import sun.security.ssl.SSLExtension.ExtensionConsumer;
+ import static sun.security.ssl.SSLExtension.SH_MAX_FRAGMENT_LENGTH;
+ import sun.security.ssl.SSLExtension.SSLExtensionSpec;
+ import sun.security.ssl.SSLHandshake.HandshakeMessage;
! /**
! * Pack of the "max_fragment_length" extensions [RFC6066].
*/
! final class MaxFragExtension {
! static final HandshakeProducer chNetworkProducer =
! new CHMaxFragmentLengthProducer();
! static final ExtensionConsumer chOnLoadConcumer =
! new CHMaxFragmentLengthConsumer();
!
! static final HandshakeProducer shNetworkProducer =
! new SHMaxFragmentLengthProducer();
! static final ExtensionConsumer shOnLoadConcumer =
! new SHMaxFragmentLengthConsumer();
! static final HandshakeConsumer shOnTradeConsumer =
! new SHMaxFragmentLengthUpdate();
!
! static final HandshakeProducer eeNetworkProducer =
! new EEMaxFragmentLengthProducer();
! static final ExtensionConsumer eeOnLoadConcumer =
! new EEMaxFragmentLengthConsumer();
! static final HandshakeConsumer eeOnTradeConsumer =
! new EEMaxFragmentLengthUpdate();
!
! static final SSLStringize maxFragLenStringize =
! new MaxFragLenStringize();
!
! /**
! * The "max_fragment_length" extension [RFC 6066].
! */
! static final class MaxFragLenSpec implements SSLExtensionSpec {
! byte id;
!
! private MaxFragLenSpec(byte id) {
! this.id = id;
! }
!
! private MaxFragLenSpec(ByteBuffer buffer) throws IOException {
! if (buffer.remaining() != 1) {
! throw new SSLProtocolException(
! "Invalid max_fragment_length extension data");
! }
!
! this.id = buffer.get();
! }
!
! @Override
! public String toString() {
! return MaxFragLenEnum.nameOf(id);
! }
! }
!
! private static final class MaxFragLenStringize implements SSLStringize {
! @Override
! public String toString(ByteBuffer buffer) {
! try {
! return (new MaxFragLenSpec(buffer)).toString();
! } catch (IOException ioe) {
! // For debug logging only, so please swallow exceptions.
! return ioe.getMessage();
! }
! }
! }
!
! static enum MaxFragLenEnum {
! MFL_512 ((byte)0x01, 512, "2^9"),
! MFL_1024 ((byte)0x02, 1024, "2^10"),
! MFL_2048 ((byte)0x03, 2048, "2^11"),
! MFL_4096 ((byte)0x04, 4096, "2^12");
! final byte id;
! final int fragmentSize;
! final String description;
! private MaxFragLenEnum(byte id, int fragmentSize, String description) {
! this.id = id;
! this.fragmentSize = fragmentSize;
! this.description = description;
! }
!
! private static MaxFragLenEnum valueOf(byte id) {
! for (MaxFragLenEnum mfl : MaxFragLenEnum.values()) {
! if (mfl.id == id) {
! return mfl;
! }
! }
!
! return null;
! }
!
! private static String nameOf(byte id) {
! for (MaxFragLenEnum mfl : MaxFragLenEnum.values()) {
! if (mfl.id == id) {
! return mfl.description;
! }
! }
! return "UNDEFINED-MAX-FRAGMENT-LENGTH(" + id + ")";
! }
! /**
! * Returns the best match enum constant of the specified
! * fragment size.
! */
! static MaxFragLenEnum valueOf(int fragmentSize) {
! if (fragmentSize <= 0) {
! return null;
! } else if (fragmentSize < 1024) {
! return MFL_512;
} else if (fragmentSize < 2048) {
! return MFL_1024;
} else if (fragmentSize < 4096) {
! return MFL_2048;
! } else if (fragmentSize == 4096) {
! return MFL_4096;
! }
!
! return null;
! }
! }
!
! /**
! * Network data producer of a "max_fragment_length" extension in
! * the ClientHello handshake message.
! */
! private static final
! class CHMaxFragmentLengthProducer implements HandshakeProducer {
! // Prevent instantiation of this class.
! private CHMaxFragmentLengthProducer() {
! // blank
! }
!
! @Override
! public byte[] produce(ConnectionContext context,
! HandshakeMessage message) throws IOException {
! // The producing happens in client side only.
! ClientHandshakeContext chc = (ClientHandshakeContext)context;
!
! // Is it a supported and enabled extension?
! if (!chc.sslConfig.isAvailable(CH_MAX_FRAGMENT_LENGTH)) {
! if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
! SSLLogger.fine(
! "Ignore unavailable max_fragment_length extension");
! }
! return null;
! }
!
! // Produce the extension and update the context.
! int requestedMFLength;
! if (chc.isResumption && (chc.resumingSession != null)) {
! // The same extension should be sent for resumption.
! requestedMFLength =
! chc.resumingSession.getNegotiatedMaxFragSize();
! } else if (chc.sslConfig.maximumPacketSize != 0) {
! // Maybe we can calculate the fragment size more accurate
! // by condering the enabled cipher suites in the future.
! requestedMFLength = chc.sslConfig.maximumPacketSize;
! if (chc.sslContext.isDTLS()) {
! requestedMFLength -= DTLSRecord.maxPlaintextPlusSize;
} else {
! requestedMFLength -= SSLRecord.maxPlaintextPlusSize;
}
+ } else {
+ // Need no max_fragment_length extension.
+ requestedMFLength = -1;
}
! MaxFragLenEnum mfl = MaxFragLenEnum.valueOf(requestedMFLength);
! if (mfl != null) {
! // update the context.
! chc.handshakeExtensions.put(
! CH_MAX_FRAGMENT_LENGTH, new MaxFragLenSpec(mfl.id));
! return new byte[] { mfl.id };
! } else {
! // log and ignore, no MFL extension.
! chc.maxFragmentLength = -1;
! if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
! SSLLogger.fine(
! "No available max_fragment_length extension can " +
! "be used for fragment size of " +
! requestedMFLength + "bytes");
! }
}
! return null;
}
}
! /**
! * Network data consumer of a "max_fragment_length" extension in
! * the ClientHello handshake message.
! */
! private static final
! class CHMaxFragmentLengthConsumer implements ExtensionConsumer {
! // Prevent instantiation of this class.
! private CHMaxFragmentLengthConsumer() {
! // blank
! }
!
@Override
! public void consume(ConnectionContext context,
! HandshakeMessage message, ByteBuffer buffer) throws IOException {
! // The comsuming happens in server side only.
! ServerHandshakeContext shc = (ServerHandshakeContext)context;
!
! if (!shc.sslConfig.isAvailable(CH_MAX_FRAGMENT_LENGTH)) {
! if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
! SSLLogger.fine(
! "Ignore unavailable max_fragment_length extension");
! }
! return; // ignore the extension
! }
!
! // Parse the extension.
! MaxFragLenSpec spec;
! try {
! spec = new MaxFragLenSpec(buffer);
! } catch (IOException ioe) {
! shc.conContext.fatal(Alert.UNEXPECTED_MESSAGE, ioe);
! return; // fatal() always throws, make the compiler happy.
! }
!
! MaxFragLenEnum mfle = MaxFragLenEnum.valueOf(spec.id);
! if (mfle == null) {
! shc.conContext.fatal(Alert.ILLEGAL_PARAMETER,
! "the requested maximum fragment length is other " +
! "than the allowed values");
! }
!
! // Update the context.
! shc.maxFragmentLength = mfle.fragmentSize;
! shc.handshakeExtensions.put(CH_MAX_FRAGMENT_LENGTH, spec);
!
! // No impact on session resumption.
! }
! }
!
! /**
! * Network data producer of a "max_fragment_length" extension in
! * the ServerHello handshake message.
! */
! private static final
! class SHMaxFragmentLengthProducer implements HandshakeProducer {
! // Prevent instantiation of this class.
! private SHMaxFragmentLengthProducer() {
! // blank
}
@Override
! public byte[] produce(ConnectionContext context,
! HandshakeMessage message) throws IOException {
! // The producing happens in server side only.
! ServerHandshakeContext shc = (ServerHandshakeContext)context;
!
! // In response to "max_fragment_length" extension request only
! MaxFragLenSpec spec = (MaxFragLenSpec)
! shc.handshakeExtensions.get(CH_MAX_FRAGMENT_LENGTH);
! if (spec == null) {
! if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
! SSLLogger.finest(
! "Ignore unavailable max_fragment_length extension");
! }
! return null; // ignore the extension
! }
!
! if ((shc.maxFragmentLength > 0) &&
! (shc.sslConfig.maximumPacketSize != 0)) {
! int estimatedMaxFragSize =
! shc.negotiatedCipherSuite.calculatePacketSize(
! shc.maxFragmentLength, shc.negotiatedProtocol,
! shc.sslContext.isDTLS());
! if (estimatedMaxFragSize > shc.sslConfig.maximumPacketSize) {
! // For better interoperability, abort the maximum
! // fragment length negotiation, rather than terminate
! // the connection with a fatal alert.
! if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
! SSLLogger.fine(
! "Abort the maximum fragment length negotiation, " +
! "may overflow the maximum packet size limit.");
! }
! shc.maxFragmentLength = -1;
! }
}
! // update the context
! if (shc.maxFragmentLength > 0) {
! shc.handshakeSession.setNegotiatedMaxFragSize(
! shc.maxFragmentLength);
! shc.conContext.inputRecord.changeFragmentSize(
! shc.maxFragmentLength);
! shc.conContext.outputRecord.changeFragmentSize(
! shc.maxFragmentLength);
!
! // The response extension data is the same as the requested one.
! shc.handshakeExtensions.put(SH_MAX_FRAGMENT_LENGTH, spec);
! return new byte[] { spec.id };
! }
!
! return null;
! }
}
! /**
! * Network data consumer of a "max_fragment_length" extension in
! * the ServerHello handshake message.
! */
! private static final
! class SHMaxFragmentLengthConsumer implements ExtensionConsumer {
! // Prevent instantiation of this class.
! private SHMaxFragmentLengthConsumer() {
! // blank
}
! @Override
! public void consume(ConnectionContext context,
! HandshakeMessage message, ByteBuffer buffer) throws IOException {
!
! // The comsuming happens in client side only.
! ClientHandshakeContext chc = (ClientHandshakeContext)context;
!
! // In response to "max_fragment_length" extension request only
! MaxFragLenSpec requestedSpec = (MaxFragLenSpec)
! chc.handshakeExtensions.get(CH_MAX_FRAGMENT_LENGTH);
! if (requestedSpec == null) {
! chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,
! "Unexpected max_fragment_length extension in ServerHello");
}
! // Parse the extension.
! MaxFragLenSpec spec;
! try {
! spec = new MaxFragLenSpec(buffer);
! } catch (IOException ioe) {
! chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE, ioe);
! return; // fatal() always throws, make the compiler happy.
! }
!
! if (spec.id != requestedSpec.id) {
! chc.conContext.fatal(Alert.ILLEGAL_PARAMETER,
! "The maximum fragment length response is not requested");
! }
!
! MaxFragLenEnum mfle = MaxFragLenEnum.valueOf(spec.id);
! if (mfle == null) {
! chc.conContext.fatal(Alert.ILLEGAL_PARAMETER,
! "the requested maximum fragment length is other " +
! "than the allowed values");
! }
!
! // update the context
! chc.maxFragmentLength = mfle.fragmentSize;
! chc.handshakeExtensions.put(SH_MAX_FRAGMENT_LENGTH, spec);
}
}
+ /**
+ * After session creation consuming of a "max_fragment_length"
+ * extension in the ClientHello handshake message.
+ */
+ private static final class SHMaxFragmentLengthUpdate
+ implements HandshakeConsumer {
+
+ // Prevent instantiation of this class.
+ private SHMaxFragmentLengthUpdate() {
+ // blank
+ }
+
@Override
! public void consume(ConnectionContext context,
! HandshakeMessage message) throws IOException {
! // The comsuming happens in client side only.
! ClientHandshakeContext chc = (ClientHandshakeContext)context;
!
! MaxFragLenSpec spec = (MaxFragLenSpec)
! chc.handshakeExtensions.get(SH_MAX_FRAGMENT_LENGTH);
! if (spec == null) {
! // Ignore, no "max_fragment_length" extension response.
! return;
! }
!
! if ((chc.maxFragmentLength > 0) &&
! (chc.sslConfig.maximumPacketSize != 0)) {
! int estimatedMaxFragSize =
! chc.negotiatedCipherSuite.calculatePacketSize(
! chc.maxFragmentLength, chc.negotiatedProtocol,
! chc.sslContext.isDTLS());
! if (estimatedMaxFragSize > chc.sslConfig.maximumPacketSize) {
! // For better interoperability, abort the maximum
! // fragment length negotiation, rather than terminate
! // the connection with a fatal alert.
! if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
! SSLLogger.fine(
! "Abort the maximum fragment length negotiation, " +
! "may overflow the maximum packet size limit.");
! }
! chc.maxFragmentLength = -1;
! }
! }
!
! // update the context
! if (chc.maxFragmentLength > 0) {
! chc.handshakeSession.setNegotiatedMaxFragSize(
! chc.maxFragmentLength);
! chc.conContext.inputRecord.changeFragmentSize(
! chc.maxFragmentLength);
! chc.conContext.outputRecord.changeFragmentSize(
! chc.maxFragmentLength);
! }
! }
! }
!
! /**
! * Network data producer of a "max_fragment_length" extension in
! * the EncryptedExtensions handshake message.
! */
! private static final
! class EEMaxFragmentLengthProducer implements HandshakeProducer {
! // Prevent instantiation of this class.
! private EEMaxFragmentLengthProducer() {
! // blank
! }
!
! @Override
! public byte[] produce(ConnectionContext context,
! HandshakeMessage message) throws IOException {
! // The producing happens in server side only.
! ServerHandshakeContext shc = (ServerHandshakeContext)context;
!
! // In response to "max_fragment_length" extension request only
! MaxFragLenSpec spec = (MaxFragLenSpec)
! shc.handshakeExtensions.get(CH_MAX_FRAGMENT_LENGTH);
! if (spec == null) {
! if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
! SSLLogger.finest(
! "Ignore unavailable max_fragment_length extension");
! }
! return null; // ignore the extension
! }
!
! if ((shc.maxFragmentLength > 0) &&
! (shc.sslConfig.maximumPacketSize != 0)) {
! int estimatedMaxFragSize =
! shc.negotiatedCipherSuite.calculatePacketSize(
! shc.maxFragmentLength, shc.negotiatedProtocol,
! shc.sslContext.isDTLS());
! if (estimatedMaxFragSize > shc.sslConfig.maximumPacketSize) {
! // For better interoperability, abort the maximum
! // fragment length negotiation, rather than terminate
! // the connection with a fatal alert.
! if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
! SSLLogger.fine(
! "Abort the maximum fragment length negotiation, " +
! "may overflow the maximum packet size limit.");
! }
! shc.maxFragmentLength = -1;
! }
! }
!
! // update the context
! if (shc.maxFragmentLength > 0) {
! shc.handshakeSession.setNegotiatedMaxFragSize(
! shc.maxFragmentLength);
! shc.conContext.inputRecord.changeFragmentSize(
! shc.maxFragmentLength);
! shc.conContext.outputRecord.changeFragmentSize(
! shc.maxFragmentLength);
!
! // The response extension data is the same as the requested one.
! shc.handshakeExtensions.put(EE_MAX_FRAGMENT_LENGTH, spec);
! return new byte[] { spec.id };
! }
!
! return null;
! }
! }
!
! /**
! * Network data consumer of a "max_fragment_length" extension in the
! * EncryptedExtensions handshake message.
! */
! private static final
! class EEMaxFragmentLengthConsumer implements ExtensionConsumer {
! // Prevent instantiation of this class.
! private EEMaxFragmentLengthConsumer() {
! // blank
! }
!
! @Override
! public void consume(ConnectionContext context,
! HandshakeMessage message, ByteBuffer buffer) throws IOException {
! // The comsuming happens in client side only.
! ClientHandshakeContext chc = (ClientHandshakeContext)context;
!
! // In response to "max_fragment_length" extension request only
! MaxFragLenSpec requestedSpec = (MaxFragLenSpec)
! chc.handshakeExtensions.get(CH_MAX_FRAGMENT_LENGTH);
! if (requestedSpec == null) {
! chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,
! "Unexpected max_fragment_length extension in ServerHello");
! }
!
! // Parse the extension.
! MaxFragLenSpec spec;
! try {
! spec = new MaxFragLenSpec(buffer);
! } catch (IOException ioe) {
! chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE, ioe);
! return; // fatal() always throws, make the compiler happy.
! }
!
! if (spec.id != requestedSpec.id) {
! chc.conContext.fatal(Alert.ILLEGAL_PARAMETER,
! "The maximum fragment length response is not requested");
! }
!
! MaxFragLenEnum mfle = MaxFragLenEnum.valueOf(spec.id);
! if (mfle == null) {
! chc.conContext.fatal(Alert.ILLEGAL_PARAMETER,
! "the requested maximum fragment length is other " +
! "than the allowed values");
! }
!
! // update the context
! chc.maxFragmentLength = mfle.fragmentSize;
! chc.handshakeExtensions.put(EE_MAX_FRAGMENT_LENGTH, spec);
! }
! }
!
! /**
! * After session creation consuming of a "max_fragment_length"
! * extension in the EncryptedExtensions handshake message.
! */
! private static final
! class EEMaxFragmentLengthUpdate implements HandshakeConsumer {
! // Prevent instantiation of this class.
! private EEMaxFragmentLengthUpdate() {
! // blank
! }
!
! @Override
! public void consume(ConnectionContext context,
! HandshakeMessage message) throws IOException {
! // The comsuming happens in client side only.
! ClientHandshakeContext chc = (ClientHandshakeContext)context;
!
! MaxFragLenSpec spec = (MaxFragLenSpec)
! chc.handshakeExtensions.get(EE_MAX_FRAGMENT_LENGTH);
! if (spec == null) {
! // Ignore, no "max_fragment_length" extension response.
! return;
! }
!
! if ((chc.maxFragmentLength > 0) &&
! (chc.sslConfig.maximumPacketSize != 0)) {
! int estimatedMaxFragSize =
! chc.negotiatedCipherSuite.calculatePacketSize(
! chc.maxFragmentLength, chc.negotiatedProtocol,
! chc.sslContext.isDTLS());
! if (estimatedMaxFragSize > chc.sslConfig.maximumPacketSize) {
! // For better interoperability, abort the maximum
! // fragment length negotiation, rather than terminate
! // the connection with a fatal alert.
! if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
! SSLLogger.fine(
! "Abort the maximum fragment length negotiation, " +
! "may overflow the maximum packet size limit.");
! }
! chc.maxFragmentLength = -1;
! }
! }
!
! // update the context
! if (chc.maxFragmentLength > 0) {
! chc.handshakeSession.setNegotiatedMaxFragSize(
! chc.maxFragmentLength);
! chc.conContext.inputRecord.changeFragmentSize(
! chc.maxFragmentLength);
! chc.conContext.outputRecord.changeFragmentSize(
! chc.maxFragmentLength);
! }
! }
}
}
< prev index next >