package org.webpieces.httpcommon.api; import java.util.List; import java.util.concurrent.CompletableFuture; import org.webpieces.data.api.DataWrapper; import org.webpieces.httpparser.api.dto.HttpRequest; import org.webpieces.httpparser.api.dto.HttpResponse; import com.webpieces.http2parser.api.dto.lib.Http2Header; public interface ResponseListener { /** * This is sort of a hard api issue to solve. When you send a request out to an http server * for http 1.1, the server can do one of 3 things * * 1. send back a single response with no body * 2. send back a response with a body (this body could be quite large) * 3. send back a response, then send as many chunks as it wants followed by a last chunk(size=0) * 4. send back a response, then infinitely stream chunks (some apis like twitter do this) * * This makes the callback api have a larger surface area than desired. The incomingResponse * method will have isComplete=true in the cases of #1 or #2 above. In the case of #3, * sendData will be called over and over until the last chunk in which case isLastChunk * will be set to true and the chunk will be of size 0, but the last chunk is special in that * it can contain extra headers with it. * * NOTE: All HttpChunks can contain extensions as well. Those are dropped. * * For Http 2, the server could send back a PUSH_PROMISE which has an imputed request, so we * need to pass back the imputed request from the PUSH_PROMISE message. For http1.1 responses * and http2 'normal' responses, we just pass back the request that we started with here. * * For Http2, only 3 and 4 are possible, so 'incomingResponse' will be called once the header * has arrived, and sendData will be called for each dataframe that follows. If there is no * data after the header (eg a HEAD request) then incomingResponse may be called with isComplete, * but it's possible that an empty dataframe will be sent, in which case incomignData will be * called with an empty dataWrapper and isLastData set to true. * * To support HTTP2 we need to pass the 'request' back with the response because the * server might push a response with an implied request. * @param resp The HttpResponse message including body if there is one * @param req the originating or presumed request * @param id an id to help us map incomingResponses to incomingDatas. UNUSED in HTTP1.1. In * HTTP1.1 you just have to take them serially-- ie all incomingdatas that show up * between incomingresponses belong to the prior incomingresponse. * @param isComplete false if the transfer encoding is chunked or http/2 in which case */ void incomingResponse(HttpResponse resp, HttpRequest req, ResponseId id, boolean isComplete); /** * * sendData returns a future because we want to be able to signal that we're * done processing this data and the flow control window can be opened back up again. * * @param data * @param id * @param isComplete */ // maybe add optional chunk or chunk extension, or not CompletableFuture<Void> incomingData(DataWrapper data, ResponseId id, boolean isComplete); /** * At the end of a response we might have more headers. Here they are. * * @param headers * @param id * @param isComplete * @return */ void incomingTrailer(List<Http2Header> headers, ResponseId id, boolean isComplete); void failure(Throwable e); }