Search in sources :

Example 1 with WritePendingException

use of java.nio.channels.WritePendingException in project jetty.project by eclipse.

the class HTTP2Test method testInvalidAPIUsageOnServer.

@Test
public void testInvalidAPIUsageOnServer() throws Exception {
    long sleep = 1000;
    CountDownLatch completeLatch = new CountDownLatch(2);
    start(new ServerSessionListener.Adapter() {

        @Override
        public Stream.Listener onNewStream(Stream stream, HeadersFrame frame) {
            MetaData.Response response = new MetaData.Response(HttpVersion.HTTP_2, HttpStatus.OK_200, new HttpFields());
            DataFrame dataFrame = new DataFrame(stream.getId(), BufferUtil.EMPTY_BUFFER, true);
            // The call to headers() is legal, but slow.
            new Thread(() -> {
                stream.headers(new HeadersFrame(stream.getId(), response, null, false) {

                    @Override
                    public MetaData getMetaData() {
                        sleep(2 * sleep);
                        return super.getMetaData();
                    }
                }, new Callback() {

                    @Override
                    public void succeeded() {
                        stream.data(dataFrame, NOOP);
                    }
                });
            }).start();
            // Wait for the headers() call to happen.
            sleep(sleep);
            // This data call is illegal because it does not
            // wait for the previous callback to complete.
            stream.data(dataFrame, new Callback() {

                @Override
                public void failed(Throwable x) {
                    if (x instanceof WritePendingException) {
                        // Expected.
                        completeLatch.countDown();
                    }
                }
            });
            return null;
        }
    });
    Session session = newClient(new Session.Listener.Adapter());
    MetaData.Request metaData = newRequest("GET", new HttpFields());
    HeadersFrame frame = new HeadersFrame(metaData, null, true);
    session.newStream(frame, new Promise.Adapter<>(), new Stream.Listener.Adapter() {

        @Override
        public void onData(Stream stream, DataFrame frame, Callback callback) {
            callback.succeeded();
            if (frame.isEndStream())
                completeLatch.countDown();
        }
    });
    Assert.assertTrue(completeLatch.await(5, TimeUnit.SECONDS));
}
Also used : ServerSessionListener(org.eclipse.jetty.http2.api.server.ServerSessionListener) WritePendingException(java.nio.channels.WritePendingException) DataFrame(org.eclipse.jetty.http2.frames.DataFrame) CountDownLatch(java.util.concurrent.CountDownLatch) HeadersFrame(org.eclipse.jetty.http2.frames.HeadersFrame) HttpServletResponse(javax.servlet.http.HttpServletResponse) Promise(org.eclipse.jetty.util.Promise) FuturePromise(org.eclipse.jetty.util.FuturePromise) Callback(org.eclipse.jetty.util.Callback) MetaData(org.eclipse.jetty.http.MetaData) HttpFields(org.eclipse.jetty.http.HttpFields) Stream(org.eclipse.jetty.http2.api.Stream) ServerSessionListener(org.eclipse.jetty.http2.api.server.ServerSessionListener) Session(org.eclipse.jetty.http2.api.Session) Test(org.junit.Test)

Example 2 with WritePendingException

use of java.nio.channels.WritePendingException in project tomcat by apache.

the class SecureNio2Channel method close.

/**
     * Sends a SSL close message, will not physically close the connection here.<br>
     * To close the connection, you could do something like
     * <pre><code>
     *   close();
     *   while (isOpen() &amp;&amp; !myTimeoutFunction()) Thread.sleep(25);
     *   if ( isOpen() ) close(true); //forces a close if you timed out
     * </code></pre>
     * @throws IOException if an I/O error occurs
     * @throws IOException if there is data on the outgoing network buffer and we are unable to flush it
     */
@Override
public void close() throws IOException {
    if (closing)
        return;
    closing = true;
    sslEngine.closeOutbound();
    try {
        if (!flush().get(endpoint.getConnectionTimeout(), TimeUnit.MILLISECONDS).booleanValue()) {
            throw new IOException(sm.getString("channel.nio.ssl.remainingDataDuringClose"));
        }
    } catch (InterruptedException | ExecutionException | TimeoutException e) {
        throw new IOException(sm.getString("channel.nio.ssl.remainingDataDuringClose"), e);
    } catch (WritePendingException e) {
        throw new IOException(sm.getString("channel.nio.ssl.pendingWriteDuringClose"), e);
    }
    //prep the buffer for the close message
    netOutBuffer.clear();
    //perform the close, since we called sslEngine.closeOutbound
    SSLEngineResult handshake = sslEngine.wrap(getEmptyBuf(), netOutBuffer);
    //we should be in a close state
    if (handshake.getStatus() != SSLEngineResult.Status.CLOSED) {
        throw new IOException(sm.getString("channel.nio.ssl.invalidCloseState"));
    }
    //prepare the buffer for writing
    netOutBuffer.flip();
    //if there is data to be written
    try {
        if (!flush().get(endpoint.getConnectionTimeout(), TimeUnit.MILLISECONDS).booleanValue()) {
            throw new IOException(sm.getString("channel.nio.ssl.remainingDataDuringClose"));
        }
    } catch (InterruptedException | ExecutionException | TimeoutException e) {
        throw new IOException(sm.getString("channel.nio.ssl.remainingDataDuringClose"), e);
    } catch (WritePendingException e) {
        throw new IOException(sm.getString("channel.nio.ssl.pendingWriteDuringClose"), e);
    }
    //is the channel closed?
    closed = (!netOutBuffer.hasRemaining() && (handshake.getHandshakeStatus() != HandshakeStatus.NEED_WRAP));
}
Also used : SSLEngineResult(javax.net.ssl.SSLEngineResult) WritePendingException(java.nio.channels.WritePendingException) IOException(java.io.IOException) ExecutionException(java.util.concurrent.ExecutionException) TimeoutException(java.util.concurrent.TimeoutException)

Example 3 with WritePendingException

use of java.nio.channels.WritePendingException in project tomcat by apache.

the class WsSession method sendCloseMessage.

private void sendCloseMessage(CloseReason closeReason) {
    // 125 is maximum size for the payload of a control message
    ByteBuffer msg = ByteBuffer.allocate(125);
    CloseCode closeCode = closeReason.getCloseCode();
    // CLOSED_ABNORMALLY should not be put on the wire
    if (closeCode == CloseCodes.CLOSED_ABNORMALLY) {
        // PROTOCOL_ERROR is probably better than GOING_AWAY here
        msg.putShort((short) CloseCodes.PROTOCOL_ERROR.getCode());
    } else {
        msg.putShort((short) closeCode.getCode());
    }
    String reason = closeReason.getReasonPhrase();
    if (reason != null && reason.length() > 0) {
        appendCloseReasonWithTruncation(msg, reason);
    }
    msg.flip();
    try {
        wsRemoteEndpoint.sendMessageBlock(Constants.OPCODE_CLOSE, msg, true);
    } catch (IOException | WritePendingException e) {
        // deal with the Exception
        if (log.isDebugEnabled()) {
            log.debug(sm.getString("wsSession.sendCloseFail", id), e);
        }
        wsRemoteEndpoint.close();
        // error handling
        if (closeCode != CloseCodes.CLOSED_ABNORMALLY) {
            localEndpoint.onError(this, e);
        }
    } finally {
        webSocketContainer.unregisterSession(localEndpoint, this);
    }
}
Also used : WritePendingException(java.nio.channels.WritePendingException) IOException(java.io.IOException) ByteBuffer(java.nio.ByteBuffer) CloseCode(javax.websocket.CloseReason.CloseCode)

Example 4 with WritePendingException

use of java.nio.channels.WritePendingException in project jetty.project by eclipse.

the class GzipHttpOutputInterceptor method commit.

protected void commit(ByteBuffer content, boolean complete, Callback callback) {
    // Are we excluding because of status?
    Response response = _channel.getResponse();
    int sc = response.getStatus();
    if (sc > 0 && (sc < 200 || sc == 204 || sc == 205 || sc >= 300)) {
        LOG.debug("{} exclude by status {}", this, sc);
        noCompression();
        if (sc == 304) {
            String request_etags = (String) _channel.getRequest().getAttribute("o.e.j.s.h.gzip.GzipHandler.etag");
            String response_etag = response.getHttpFields().get(HttpHeader.ETAG);
            if (request_etags != null && response_etag != null) {
                String response_etag_gzip = etagGzip(response_etag);
                if (request_etags.contains(response_etag_gzip))
                    response.getHttpFields().put(HttpHeader.ETAG, response_etag_gzip);
            }
        }
        _interceptor.write(content, complete, callback);
        return;
    }
    // Are we excluding because of mime-type?
    String ct = response.getContentType();
    if (ct != null) {
        ct = MimeTypes.getContentTypeWithoutCharset(ct);
        if (!_factory.isMimeTypeGzipable(StringUtil.asciiToLowerCase(ct))) {
            LOG.debug("{} exclude by mimeType {}", this, ct);
            noCompression();
            _interceptor.write(content, complete, callback);
            return;
        }
    }
    // Has the Content-Encoding header already been set?
    HttpFields fields = response.getHttpFields();
    String ce = fields.get(HttpHeader.CONTENT_ENCODING);
    if (ce != null) {
        LOG.debug("{} exclude by content-encoding {}", this, ce);
        noCompression();
        _interceptor.write(content, complete, callback);
        return;
    }
    // Are we the thread that commits?
    if (_state.compareAndSet(GZState.MIGHT_COMPRESS, GZState.COMMITTING)) {
        // We are varying the response due to accept encoding header.
        if (_vary != null) {
            if (fields.contains(HttpHeader.VARY))
                fields.addCSV(HttpHeader.VARY, _vary.getValues());
            else
                fields.add(_vary);
        }
        long content_length = response.getContentLength();
        if (content_length < 0 && complete)
            content_length = content.remaining();
        _deflater = _factory.getDeflater(_channel.getRequest(), content_length);
        if (_deflater == null) {
            LOG.debug("{} exclude no deflater", this);
            _state.set(GZState.NOT_COMPRESSING);
            _interceptor.write(content, complete, callback);
            return;
        }
        fields.put(GZIP._contentEncoding);
        _crc.reset();
        _buffer = _channel.getByteBufferPool().acquire(_bufferSize, false);
        BufferUtil.fill(_buffer, GZIP_HEADER, 0, GZIP_HEADER.length);
        // Adjust headers
        response.setContentLength(-1);
        String etag = fields.get(HttpHeader.ETAG);
        if (etag != null)
            fields.put(HttpHeader.ETAG, etagGzip(etag));
        LOG.debug("{} compressing {}", this, _deflater);
        _state.set(GZState.COMPRESSING);
        gzip(content, complete, callback);
    } else
        callback.failed(new WritePendingException());
}
Also used : Response(org.eclipse.jetty.server.Response) HttpFields(org.eclipse.jetty.http.HttpFields) WritePendingException(java.nio.channels.WritePendingException)

Example 5 with WritePendingException

use of java.nio.channels.WritePendingException in project jetty.project by eclipse.

the class HttpOutput method write.

@Override
public void write(byte[] b, int off, int len) throws IOException {
    // Async or Blocking ?
    while (true) {
        switch(_state.get()) {
            case OPEN:
                // process blocking below
                break;
            case ASYNC:
                throw new IllegalStateException("isReady() not called");
            case READY:
                if (!_state.compareAndSet(OutputState.READY, OutputState.PENDING))
                    continue;
                // Should we aggregate?
                boolean last = isLastContentToWrite(len);
                if (!last && len <= _commitSize) {
                    if (_aggregate == null)
                        _aggregate = _channel.getByteBufferPool().acquire(getBufferSize(), _interceptor.isOptimizedForDirectBuffers());
                    // YES - fill the aggregate with content from the buffer
                    int filled = BufferUtil.fill(_aggregate, b, off, len);
                    // return if we are not complete, not full and filled all the content
                    if (filled == len && !BufferUtil.isFull(_aggregate)) {
                        if (!_state.compareAndSet(OutputState.PENDING, OutputState.ASYNC))
                            throw new IllegalStateException();
                        return;
                    }
                    // adjust offset/length
                    off += filled;
                    len -= filled;
                }
                // Do the asynchronous writing from the callback
                new AsyncWrite(b, off, len, last).iterate();
                return;
            case PENDING:
            case UNREADY:
                throw new WritePendingException();
            case ERROR:
                throw new EofException(_onError);
            case CLOSED:
                throw new EofException("Closed");
            default:
                throw new IllegalStateException();
        }
        break;
    }
    // handle blocking write
    // Should we aggregate?
    int capacity = getBufferSize();
    boolean last = isLastContentToWrite(len);
    if (!last && len <= _commitSize) {
        if (_aggregate == null)
            _aggregate = _channel.getByteBufferPool().acquire(capacity, _interceptor.isOptimizedForDirectBuffers());
        // YES - fill the aggregate with content from the buffer
        int filled = BufferUtil.fill(_aggregate, b, off, len);
        // return if we are not complete, not full and filled all the content
        if (filled == len && !BufferUtil.isFull(_aggregate))
            return;
        // adjust offset/length
        off += filled;
        len -= filled;
    }
    // flush any content from the aggregate
    if (BufferUtil.hasContent(_aggregate)) {
        write(_aggregate, last && len == 0);
        // should we fill aggregate again from the buffer?
        if (len > 0 && !last && len <= _commitSize && len <= BufferUtil.space(_aggregate)) {
            BufferUtil.append(_aggregate, b, off, len);
            return;
        }
    }
    // write any remaining content in the buffer directly
    if (len > 0) {
        // write a buffer capacity at a time to avoid JVM pooling large direct buffers
        // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6210541
        ByteBuffer view = ByteBuffer.wrap(b, off, len);
        while (len > getBufferSize()) {
            int p = view.position();
            int l = p + getBufferSize();
            view.limit(p + getBufferSize());
            write(view, false);
            len -= getBufferSize();
            view.limit(l + Math.min(len, getBufferSize()));
            view.position(l);
        }
        write(view, last);
    } else if (last) {
        write(BufferUtil.EMPTY_BUFFER, true);
    }
    if (last)
        closed();
}
Also used : EofException(org.eclipse.jetty.io.EofException) WritePendingException(java.nio.channels.WritePendingException) ByteBuffer(java.nio.ByteBuffer)

Aggregations

WritePendingException (java.nio.channels.WritePendingException)6 HttpFields (org.eclipse.jetty.http.HttpFields)3 IOException (java.io.IOException)2 ByteBuffer (java.nio.ByteBuffer)2 CountDownLatch (java.util.concurrent.CountDownLatch)2 HttpServletResponse (javax.servlet.http.HttpServletResponse)2 MetaData (org.eclipse.jetty.http.MetaData)2 Session (org.eclipse.jetty.http2.api.Session)2 Stream (org.eclipse.jetty.http2.api.Stream)2 ServerSessionListener (org.eclipse.jetty.http2.api.server.ServerSessionListener)2 DataFrame (org.eclipse.jetty.http2.frames.DataFrame)2 HeadersFrame (org.eclipse.jetty.http2.frames.HeadersFrame)2 Callback (org.eclipse.jetty.util.Callback)2 FuturePromise (org.eclipse.jetty.util.FuturePromise)2 Promise (org.eclipse.jetty.util.Promise)2 Test (org.junit.Test)2 ExecutionException (java.util.concurrent.ExecutionException)1 TimeoutException (java.util.concurrent.TimeoutException)1 SSLEngineResult (javax.net.ssl.SSLEngineResult)1 CloseCode (javax.websocket.CloseReason.CloseCode)1