use of org.springframework.core.io.buffer.DataBufferFactory in project spring-framework by spring-projects.
the class ResourceRegionEncoder method writeResourceRegion.
private Flux<DataBuffer> writeResourceRegion(ResourceRegion region, DataBufferFactory bufferFactory, @Nullable Map<String, Object> hints) {
Resource resource = region.getResource();
long position = region.getPosition();
long count = region.getCount();
if (logger.isDebugEnabled() && !Hints.isLoggingSuppressed(hints)) {
logger.debug(Hints.getLogPrefix(hints) + "Writing region " + position + "-" + (position + count) + " of [" + resource + "]");
}
Flux<DataBuffer> in = DataBufferUtils.read(resource, position, bufferFactory, this.bufferSize);
if (logger.isDebugEnabled()) {
in = in.doOnNext(buffer -> Hints.touchDataBuffer(buffer, hints, logger));
}
return DataBufferUtils.takeUntilByteCount(in, count);
}
use of org.springframework.core.io.buffer.DataBufferFactory in project spring-framework by spring-projects.
the class JsonObjectDecoder method decode.
@Override
public Flux<DataBuffer> decode(Publisher<DataBuffer> inputStream, ResolvableType elementType, MimeType mimeType, Map<String, Object> hints) {
return Flux.from(inputStream).flatMap(new Function<DataBuffer, Publisher<? extends DataBuffer>>() {
int openBraces;
int index;
int state;
boolean insideString;
ByteBuf input;
Integer writerIndex;
@Override
public Publisher<? extends DataBuffer> apply(DataBuffer buffer) {
List<DataBuffer> chunks = new ArrayList<>();
if (this.input == null) {
this.input = Unpooled.copiedBuffer(buffer.asByteBuffer());
DataBufferUtils.release(buffer);
this.writerIndex = this.input.writerIndex();
} else {
this.index = this.index - this.input.readerIndex();
this.input = Unpooled.copiedBuffer(this.input, Unpooled.copiedBuffer(buffer.asByteBuffer()));
DataBufferUtils.release(buffer);
this.writerIndex = this.input.writerIndex();
}
if (this.state == ST_CORRUPTED) {
this.input.skipBytes(this.input.readableBytes());
return Flux.error(new IllegalStateException("Corrupted stream"));
}
if (this.writerIndex > maxObjectLength) {
// buffer size exceeded maxObjectLength; discarding the complete buffer.
this.input.skipBytes(this.input.readableBytes());
reset();
return Flux.error(new IllegalStateException("object length exceeds " + maxObjectLength + ": " + this.writerIndex + " bytes discarded"));
}
DataBufferFactory dataBufferFactory = buffer.factory();
for (; /* use current index */
this.index < this.writerIndex; this.index++) {
byte c = this.input.getByte(this.index);
if (this.state == ST_DECODING_NORMAL) {
decodeByte(c, this.input, this.index);
// that the JSON object/array is complete.
if (this.openBraces == 0) {
ByteBuf json = extractObject(this.input, this.input.readerIndex(), this.index + 1 - this.input.readerIndex());
if (json != null) {
chunks.add(dataBufferFactory.wrap(json.nioBuffer()));
}
// The JSON object/array was extracted => discard the bytes from
// the input buffer.
this.input.readerIndex(this.index + 1);
// Reset the object state to get ready for the next JSON object/text
// coming along the byte stream.
reset();
}
} else if (this.state == ST_DECODING_ARRAY_STREAM) {
decodeByte(c, this.input, this.index);
if (!this.insideString && (this.openBraces == 1 && c == ',' || this.openBraces == 0 && c == ']')) {
// because the byte at position index is not a whitespace.
for (int i = this.input.readerIndex(); Character.isWhitespace(this.input.getByte(i)); i++) {
this.input.skipBytes(1);
}
// skip trailing spaces.
int idxNoSpaces = this.index - 1;
while (idxNoSpaces >= this.input.readerIndex() && Character.isWhitespace(this.input.getByte(idxNoSpaces))) {
idxNoSpaces--;
}
ByteBuf json = extractObject(this.input, this.input.readerIndex(), idxNoSpaces + 1 - this.input.readerIndex());
if (json != null) {
chunks.add(dataBufferFactory.wrap(json.nioBuffer()));
}
this.input.readerIndex(this.index + 1);
if (c == ']') {
reset();
}
}
// JSON object/array detected. Accumulate bytes until all braces/brackets are closed.
} else if (c == '{' || c == '[') {
initDecoding(c, streamArrayElements);
if (this.state == ST_DECODING_ARRAY_STREAM) {
// Discard the array bracket
this.input.skipBytes(1);
}
// Discard leading spaces in front of a JSON object/array.
} else if (Character.isWhitespace(c)) {
this.input.skipBytes(1);
} else {
this.state = ST_CORRUPTED;
return Flux.error(new IllegalStateException("invalid JSON received at byte position " + this.index + ": " + ByteBufUtil.hexDump(this.input)));
}
}
return Flux.fromIterable(chunks);
}
/**
* Override this method if you want to filter the json objects/arrays that
* get passed through the pipeline.
*/
protected ByteBuf extractObject(ByteBuf buffer, int index, int length) {
return buffer.slice(index, length).retain();
}
private void decodeByte(byte c, ByteBuf input, int index) {
if ((c == '{' || c == '[') && !this.insideString) {
this.openBraces++;
} else if ((c == '}' || c == ']') && !this.insideString) {
this.openBraces--;
} else if (c == '"') {
// also contain braces/brackets and that could lead to incorrect results.
if (!this.insideString) {
this.insideString = true;
// If the double quote wasn't escaped then this is the end of a string.
} else if (input.getByte(index - 1) != '\\') {
this.insideString = false;
}
}
}
private void initDecoding(byte openingBrace, boolean streamArrayElements) {
this.openBraces = 1;
if (openingBrace == '[' && streamArrayElements) {
this.state = ST_DECODING_ARRAY_STREAM;
} else {
this.state = ST_DECODING_NORMAL;
}
}
private void reset() {
this.insideString = false;
this.state = ST_INIT;
this.openBraces = 0;
}
});
}
use of org.springframework.core.io.buffer.DataBufferFactory in project spring-framework by spring-projects.
the class ResourceRegionHttpMessageWriter method writeRegions.
public Mono<Void> writeRegions(Publisher<? extends ResourceRegion> inputStream, MediaType contentType, ReactiveHttpOutputMessage outputMessage, Map<String, Object> hints) {
if (hints != null && hints.containsKey(BOUNDARY_STRING_HINT)) {
String boundary = (String) hints.get(BOUNDARY_STRING_HINT);
hints.put(ResourceRegionEncoder.BOUNDARY_STRING_HINT, boundary);
MediaType multipartType = MediaType.parseMediaType("multipart/byteranges;boundary=" + boundary);
outputMessage.getHeaders().setContentType(multipartType);
DataBufferFactory bufferFactory = outputMessage.bufferFactory();
Flux<DataBuffer> body = this.encoder.encode(inputStream, bufferFactory, TYPE, contentType, hints);
return outputMessage.writeWith(body);
} else {
return Mono.from(inputStream).then(region -> {
writeSingleResourceRegionHeaders(region, contentType, outputMessage);
return writeResourceRegion(region, outputMessage);
});
}
}
use of org.springframework.core.io.buffer.DataBufferFactory in project spring-framework by spring-projects.
the class TomcatRequestUpgradeStrategy method upgrade.
@Override
public Mono<Void> upgrade(ServerWebExchange exchange, WebSocketHandler handler, Optional<String> subProtocol) {
ServerHttpRequest request = exchange.getRequest();
ServerHttpResponse response = exchange.getResponse();
HttpServletRequest servletRequest = getHttpServletRequest(request);
HttpServletResponse servletResponse = getHttpServletResponse(response);
Endpoint endpoint = new StandardWebSocketHandlerAdapter(handler, session -> {
HandshakeInfo info = getHandshakeInfo(exchange, subProtocol);
DataBufferFactory factory = response.bufferFactory();
return new StandardWebSocketSession(session, info, factory);
});
String requestURI = servletRequest.getRequestURI();
DefaultServerEndpointConfig config = new DefaultServerEndpointConfig(requestURI, endpoint);
config.setSubprotocols(subProtocol.map(Collections::singletonList).orElse(Collections.emptyList()));
try {
WsServerContainer container = getContainer(servletRequest);
container.doUpgrade(servletRequest, servletResponse, config, Collections.emptyMap());
} catch (ServletException | IOException ex) {
return Mono.error(ex);
}
return Mono.empty();
}
use of org.springframework.core.io.buffer.DataBufferFactory in project spring-framework by spring-projects.
the class JettyRequestUpgradeStrategy method upgrade.
@Override
public Mono<Void> upgrade(ServerWebExchange exchange, WebSocketHandler handler, Optional<String> subProtocol) {
ServerHttpRequest request = exchange.getRequest();
ServerHttpResponse response = exchange.getResponse();
HttpServletRequest servletRequest = getHttpServletRequest(request);
HttpServletResponse servletResponse = getHttpServletResponse(response);
JettyWebSocketHandlerAdapter adapter = new JettyWebSocketHandlerAdapter(handler, session -> {
HandshakeInfo info = getHandshakeInfo(exchange, subProtocol);
DataBufferFactory factory = response.bufferFactory();
return new JettyWebSocketSession(session, info, factory);
});
startLazily(servletRequest);
boolean isUpgrade = this.factory.isUpgradeRequest(servletRequest, servletResponse);
Assert.isTrue(isUpgrade, "Not a WebSocket handshake");
try {
adapterHolder.set(new WebSocketHandlerContainer(adapter, subProtocol));
this.factory.acceptWebSocket(servletRequest, servletResponse);
} catch (IOException ex) {
return Mono.error(ex);
} finally {
adapterHolder.remove();
}
return Mono.empty();
}
Aggregations