package com.fasterxml.jackson.databind.node;

import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;

import com.fasterxml.jackson.core.util.ByteArrayBuilder;

Helper value class only used during JDK serialization: contains JSON as `byte[]`
Since:2.10
/** * Helper value class only used during JDK serialization: contains JSON as `byte[]` * * @since 2.10 */
class NodeSerialization implements java.io.Serializable, java.io.Externalizable { // To avoid malicious input only allocate up to 100k protected final static int LONGEST_EAGER_ALLOC = 100_000; private static final long serialVersionUID = 1L; public byte[] json; public NodeSerialization() { } public NodeSerialization(byte[] b) { json = b; } protected Object readResolve() { try { return InternalNodeMapper.bytesToNode(json); } catch (IOException e) { throw new IllegalArgumentException("Failed to JDK deserialize `JsonNode` value: "+e.getMessage(), e); } } public static NodeSerialization from(Object o) { try { return new NodeSerialization(InternalNodeMapper.valueToBytes(o)); } catch (IOException e) { throw new IllegalArgumentException("Failed to JDK serialize `"+o.getClass().getSimpleName()+"` value: "+e.getMessage(), e); } } @Override public void writeExternal(ObjectOutput out) throws IOException { out.writeInt(json.length); out.write(json); } @Override public void readExternal(ObjectInput in) throws IOException { final int len = in.readInt(); json = _read(in, len); } private byte[] _read(ObjectInput in, int expLen) throws IOException { // Common case, just read directly if (expLen <= LONGEST_EAGER_ALLOC) { byte[] result = new byte[expLen]; in.readFully(result, 0, expLen); return result; } // but longer content needs more care to avoid DoS by maliciously crafted data // (this wrt [databind#3328] try (final ByteArrayBuilder bb = new ByteArrayBuilder(LONGEST_EAGER_ALLOC)) { byte[] buffer = bb.resetAndGetFirstSegment(); int outOffset = 0; while (true) { int toRead = Math.min(buffer.length - outOffset, expLen); in.readFully(buffer, 0, toRead); expLen -= toRead; outOffset += toRead; // Did we get everything we needed? If so, we are done if (expLen == 0) { return bb.completeAndCoalesce(outOffset); } // Or perhaps we filled the current segment? If so, finish, get next if (outOffset == buffer.length) { buffer = bb.finishCurrentSegment(); outOffset = 0; } } } } }