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

org.smartboot.http.client.impl.HttpMessageProcessor Maven / Gradle / Ivy

There is a newer version: 1.4.3
Show newest version
/*******************************************************************************
 * Copyright (c) 2017-2021, org.smartboot. All rights reserved.
 * project name: smart-http
 * file name: HttpMessageProcessor.java
 * Date: 2021-02-08
 * Author: sandao ([email protected])
 ******************************************************************************/

package org.smartboot.http.client.impl;

import org.smartboot.http.client.ResponseHandler;
import org.smartboot.http.common.enums.DecodePartEnum;
import org.smartboot.http.common.enums.HeaderNameEnum;
import org.smartboot.http.common.enums.HeaderValueEnum;
import org.smartboot.socket.StateMachineEnum;
import org.smartboot.socket.extension.processor.AbstractMessageProcessor;
import org.smartboot.socket.transport.AioSession;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.AbstractQueue;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ExecutorService;

/**
 * @author 三刀
 * @version V1.0 , 2018/6/10
 */
public class HttpMessageProcessor extends AbstractMessageProcessor {
    private final ExecutorService executorService;
    private final Map> map = new ConcurrentHashMap<>();

    public HttpMessageProcessor() {
        this(null);
    }

    public HttpMessageProcessor(ExecutorService executorService) {
        this.executorService = executorService;
    }

    @Override
    public void process0(AioSession session, Response response) {
        ResponseAttachment responseAttachment = session.getAttachment();
        AbstractQueue queue = map.get(session);
        QueueUnit queueUnit = queue.peek();
        ResponseHandler responseHandler = queueUnit.getResponseHandler();

        switch (response.getDecodePartEnum()) {
            case HEADER_FINISH:
                doHttpHeader(response, responseHandler);
            case BODY:
                doHttpBody(response, session.readBuffer(), responseAttachment, responseHandler);
                if (response.getDecodePartEnum() != DecodePartEnum.FINISH) {
                    break;
                }
            case FINISH:
                queue.poll();
                responseAttachment.setDecoder(null);
                if (executorService == null) {
                    responseCallback(session, response, queueUnit);
                } else {
                    session.awaitRead();
                    executorService.execute(() -> {
                        responseCallback(session, response, queueUnit);
                        session.signalRead();
                    });
                }
                break;
            default:
        }
    }

    private void responseCallback(AioSession session, Response response, QueueUnit queueUnit) {
        try {
            queueUnit.getFuture().complete(response);
        } finally {
            if (!HeaderValueEnum.KEEPALIVE.getName().equalsIgnoreCase(response.getHeader(HeaderNameEnum.CONNECTION.getName()))) {
                session.close(false);
            } else {
                response.reset();
            }
        }
    }

    private void doHttpBody(Response response, ByteBuffer readBuffer, ResponseAttachment responseAttachment, ResponseHandler responseHandler) {
        if (responseHandler.onBodyStream(readBuffer, response)) {
            response.setDecodePartEnum(DecodePartEnum.FINISH);
        } else if (readBuffer.hasRemaining()) {
            //半包,继续读数据
            responseAttachment.setDecoder(HttpResponseProtocol.BODY_CONTINUE_DECODER);
        }
    }

    private void doHttpHeader(Response response, ResponseHandler responseHandler) {
        response.setDecodePartEnum(DecodePartEnum.BODY);
        try {
            responseHandler.onHeaderComplete(response);
        } catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    @Override
    public void stateEvent0(AioSession session, StateMachineEnum stateMachineEnum, Throwable throwable) {
        if (throwable != null) {
            AbstractQueue queue = map.get(session);
            if (queue != null) {
                QueueUnit future;
                while ((future = queue.poll()) != null) {
                    future.getFuture().completeExceptionally(throwable);
                }
            }
        }
        switch (stateMachineEnum) {
            case NEW_SESSION:
                map.put(session, new ConcurrentLinkedQueue<>());
                ResponseAttachment attachment = new ResponseAttachment(new Response(session));
                session.setAttachment(attachment);
                break;
            case PROCESS_EXCEPTION:
                session.close();
                break;
            case DECODE_EXCEPTION:
                throwable.printStackTrace();
                break;
            case SESSION_CLOSED:
                AbstractQueue queue = map.remove(session);
                QueueUnit future;
                while ((future = queue.poll()) != null) {
                    future.getFuture().completeExceptionally(new IOException("client is closed"));
                }
                break;
        }
    }

    public AbstractQueue getQueue(AioSession aioSession) {
        return map.get(aioSession);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy