Search in sources :

Example 6 with DataBufferFactory

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();
}
Also used : HttpServletRequest(javax.servlet.http.HttpServletRequest) ServletServerHttpRequest(org.springframework.http.server.reactive.ServletServerHttpRequest) ServerHttpRequest(org.springframework.http.server.reactive.ServerHttpRequest) JettyWebSocketSession(org.springframework.web.reactive.socket.adapter.JettyWebSocketSession) HttpServletResponse(javax.servlet.http.HttpServletResponse) IOException(java.io.IOException) DataBufferFactory(org.springframework.core.io.buffer.DataBufferFactory) ServerHttpResponse(org.springframework.http.server.reactive.ServerHttpResponse) ServletServerHttpResponse(org.springframework.http.server.reactive.ServletServerHttpResponse) JettyWebSocketHandlerAdapter(org.springframework.web.reactive.socket.adapter.JettyWebSocketHandlerAdapter) HandshakeInfo(org.springframework.web.reactive.socket.HandshakeInfo)

Example 7 with DataBufferFactory

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();
}
Also used : WsServerContainer(org.apache.tomcat.websocket.server.WsServerContainer) StandardWebSocketHandlerAdapter(org.springframework.web.reactive.socket.adapter.StandardWebSocketHandlerAdapter) ServletServerHttpRequest(org.springframework.http.server.reactive.ServletServerHttpRequest) ServerHttpRequest(org.springframework.http.server.reactive.ServerHttpRequest) HttpServletResponse(javax.servlet.http.HttpServletResponse) IOException(java.io.IOException) ServerHttpResponse(org.springframework.http.server.reactive.ServerHttpResponse) ServletServerHttpResponse(org.springframework.http.server.reactive.ServletServerHttpResponse) HttpServletRequest(javax.servlet.http.HttpServletRequest) ServletException(javax.servlet.ServletException) Endpoint(javax.websocket.Endpoint) StandardWebSocketSession(org.springframework.web.reactive.socket.adapter.StandardWebSocketSession) Collections(java.util.Collections) DataBufferFactory(org.springframework.core.io.buffer.DataBufferFactory) HandshakeInfo(org.springframework.web.reactive.socket.HandshakeInfo)

Example 8 with DataBufferFactory

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;
        }
    });
}
Also used : Publisher(org.reactivestreams.Publisher) ByteBuf(io.netty.buffer.ByteBuf) ArrayList(java.util.ArrayList) List(java.util.List) DataBufferFactory(org.springframework.core.io.buffer.DataBufferFactory) DataBuffer(org.springframework.core.io.buffer.DataBuffer)

Example 9 with DataBufferFactory

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);
        });
    }
}
Also used : MediaType(org.springframework.http.MediaType) DataBufferFactory(org.springframework.core.io.buffer.DataBufferFactory) DataBuffer(org.springframework.core.io.buffer.DataBuffer)

Aggregations

DataBufferFactory (org.springframework.core.io.buffer.DataBufferFactory)9 DataBuffer (org.springframework.core.io.buffer.DataBuffer)5 Publisher (org.reactivestreams.Publisher)4 IOException (java.io.IOException)3 List (java.util.List)3 MediaType (org.springframework.http.MediaType)3 ArrayList (java.util.ArrayList)2 Collections (java.util.Collections)2 Map (java.util.Map)2 HttpServletRequest (javax.servlet.http.HttpServletRequest)2 HttpServletResponse (javax.servlet.http.HttpServletResponse)2 ResolvableType (org.springframework.core.ResolvableType)2 CodecException (org.springframework.core.codec.CodecException)2 Encoder (org.springframework.core.codec.Encoder)2 ServerHttpRequest (org.springframework.http.server.reactive.ServerHttpRequest)2 ServerHttpResponse (org.springframework.http.server.reactive.ServerHttpResponse)2 ServletServerHttpRequest (org.springframework.http.server.reactive.ServletServerHttpRequest)2 ServletServerHttpResponse (org.springframework.http.server.reactive.ServletServerHttpResponse)2 Assert (org.springframework.util.Assert)2 HandshakeInfo (org.springframework.web.reactive.socket.HandshakeInfo)2