All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.jsync.http.impl.DefaultHttpClientResponse Maven / Gradle / Ivy

There is a newer version: 1.10.13
Show newest version
/*
 * Copyright (c) 2011-2013 The original author or authors
 * ------------------------------------------------------
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * and Apache License v2.0 which accompanies this distribution.
 *
 *     The Eclipse Public License is available at
 *     http://www.eclipse.org/legal/epl-v10.html
 *
 *     The Apache License v2.0 is available at
 *     http://www.opensource.org/licenses/apache2.0.php
 *
 * You may elect to redistribute this code under either of these licenses.
 */

package io.jsync.http.impl;

import io.jsync.Async;
import io.jsync.Handler;
import io.jsync.MultiMap;
import io.jsync.VoidHandler;
import io.jsync.buffer.Buffer;
import io.jsync.http.HttpClientResponse;
import io.jsync.net.NetSocket;
import io.netty.handler.codec.http.DefaultHttpHeaders;
import io.netty.handler.codec.http.HttpResponse;
import io.netty.handler.codec.http.LastHttpContent;

import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.List;
import java.util.Queue;

/**
 * @author Tim Fox
 */
public class DefaultHttpClientResponse implements HttpClientResponse {

    private final int statusCode;
    private final String statusMessage;
    private final DefaultHttpClientRequest request;
    private final Async async;
    private final ClientConnection conn;
    private final HttpResponse response;
    private Handler dataHandler;
    private Handler endHandler;
    private Handler exceptionHandler;
    private LastHttpContent trailer;
    private boolean paused;
    private Queue pausedChunks;
    private boolean hasPausedEnd;
    private LastHttpContent pausedTrailer;
    private NetSocket netSocket;

    // Cache these for performance
    private MultiMap headers;
    private MultiMap trailers;
    private List cookies;

    DefaultHttpClientResponse(Async async, DefaultHttpClientRequest request, ClientConnection conn, HttpResponse response) {
        this.async = async;
        this.statusCode = response.getStatus().code();
        this.statusMessage = response.getStatus().reasonPhrase();
        this.request = request;
        this.conn = conn;
        this.response = response;
    }

    @Override
    public int statusCode() {
        return statusCode;
    }

    @Override
    public String statusMessage() {
        return statusMessage;
    }

    @Override
    public MultiMap headers() {
        if (headers == null) {
            headers = new HttpHeadersAdapter(response.headers());
        }
        return headers;
    }

    @Override
    public MultiMap trailers() {
        if (trailers == null) {
            trailers = new HttpHeadersAdapter(new DefaultHttpHeaders());
        }
        return trailers;
    }

    @Override
    public List cookies() {
        if (cookies == null) {
            cookies = new ArrayList<>();
            cookies.addAll(response.headers().getAll(io.jsync.http.HttpHeaders.SET_COOKIE));
            if (trailer != null) {
                cookies.addAll(trailer.trailingHeaders().getAll(io.jsync.http.HttpHeaders.SET_COOKIE));
            }
        }
        return cookies;
    }

    @Override
    public HttpClientResponse dataHandler(Handler dataHandler) {
        this.dataHandler = dataHandler;
        return this;
    }

    @Override
    public HttpClientResponse endHandler(Handler endHandler) {
        this.endHandler = endHandler;
        return this;
    }

    @Override
    public HttpClientResponse exceptionHandler(Handler exceptionHandler) {
        this.exceptionHandler = exceptionHandler;
        return this;
    }

    @Override
    public HttpClientResponse pause() {
        paused = true;
        conn.doPause();
        return this;
    }

    @Override
    public HttpClientResponse resume() {
        paused = false;
        doResume();
        conn.doResume();
        return this;
    }

    @Override
    public HttpClientResponse bodyHandler(final Handler bodyHandler) {
        final BodyHandler handler = new BodyHandler();
        dataHandler(handler);
        endHandler(new VoidHandler() {
            public void handle() {
                handler.notifyHandler(bodyHandler);
            }
        });
        return this;
    }

    private void doResume() {
        if (pausedChunks != null) {
            Buffer chunk;
            while ((chunk = pausedChunks.poll()) != null) {
                final Buffer theChunk = chunk;
                async.runOnContext(new VoidHandler() {
                    @Override
                    protected void handle() {
                        handleChunk(theChunk);
                    }
                });
            }
        }
        if (hasPausedEnd) {
            final LastHttpContent theTrailer = pausedTrailer;
            async.runOnContext(new VoidHandler() {
                @Override
                protected void handle() {
                    handleEnd(theTrailer);
                }
            });
            hasPausedEnd = false;
            pausedTrailer = null;
        }
    }

    void handleChunk(Buffer data) {
        if (paused) {
            if (pausedChunks == null) {
                pausedChunks = new ArrayDeque<>();
            }
            pausedChunks.add(data);
        } else {
            request.dataReceived();
            if (dataHandler != null) {
                dataHandler.handle(data);
            }
        }
    }

    void handleEnd(LastHttpContent trailer) {
        if (paused) {
            hasPausedEnd = true;
            pausedTrailer = trailer;
        } else {
            this.trailer = trailer;
            trailers = new HttpHeadersAdapter(trailer.trailingHeaders());
            if (endHandler != null) {
                endHandler.handle(null);
            }
        }
    }

    void handleException(Throwable e) {
        if (exceptionHandler != null) {
            exceptionHandler.handle(e);
        }
    }

    @Override
    public NetSocket netSocket() {
        if (netSocket == null) {
            netSocket = conn.createNetSocket();
        }
        return netSocket;
    }


    private final class BodyHandler implements Handler {
        private Buffer body;

        @Override
        public void handle(Buffer event) {
            body().appendBuffer(event);
        }

        private Buffer body() {
            if (body == null) {
                body = new Buffer();
            }
            return body;
        }

        void notifyHandler(Handler bodyHandler) {
            bodyHandler.handle(body());
            // reset body so it can get GC'ed
            body = null;
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy