private static HttpResponseWriter aggregateFrom(CompletableFuture<?> future, HttpHeaders headers, HttpHeaders trailingHeaders, Function<Object, HttpData> contentConverter) { final HttpResponseWriter writer = HttpResponse.streaming(); future.handle((result, cause) -> { if (cause != null) { writer.close(cause); return null; } try { final HttpData content = contentConverter.apply(result); writer.write(headers); writer.write(content); if (!trailingHeaders.isEmpty()) { writer.write(trailingHeaders); } writer.close(); } catch (Exception e) { writer.close(e); } return null; }); return writer; }
private void invoke(ServiceRequestContext ctx, HttpResponseWriter res, ArmeriaHttpTransport transport, HttpChannel httpChannel) { final Queue<HttpData> out = transport.out; try { server.handle(httpChannel); httpChannel.getResponse().getHttpOutput().flush(); final Throwable cause = transport.cause; if (cause != null) { throw cause; } final HttpHeaders headers = toResponseHeaders(transport); if (res.tryWrite(headers)) { for (;;) { final HttpData data = out.poll(); if (data == null || !res.tryWrite(data)) { break; } } } } catch (Throwable t) { logger.warn("{} Failed to produce a response:", ctx, t); } finally { res.close(); } }
@Override public void onSubscribe(Subscription s) { assert subscription == null; subscription = s; writer.closeFuture().handle((unused, cause) -> { if (cause != null) { s.cancel(); } return null; }); try { writer.onDemand(new Runnable() { @Override public void run() { s.request(1); writer.onDemand(this); } }); } catch (Exception e) { onError(e); } }
@Override public void onError(Throwable cause) { if (!writer.isOpen()) { return; } try { writer.close(cause); } catch (Exception e) { // 'subscription.cancel()' would be called by the close future listener of the writer, // so we call it when we failed to close the writer. assert subscription != null; subscription.cancel(); } }
@Override public void onNext(T value) { if (!writer.isOpen()) { return; } try { // To get an exception from the converter before sending the headers. final HttpData content = contentConverter.apply(value); if (!headersSent) { writer.write(headers); headersSent = true; } writer.write(content); } catch (Exception e) { onError(e); } }
if (cause != null) { logger.warn("{} Failed to aggregate a request:", ctx, cause); res.close(HttpHeaders.of(HttpStatus.INTERNAL_SERVER_ERROR)); return null; res.close(HttpHeaders.of(HttpStatus.BAD_REQUEST)); return null; if (!res.isOpen()) { return; coyoteAdapter.get().service(coyoteReq, coyoteRes); final HttpHeaders headers = convertResponse(coyoteRes); if (res.tryWrite(headers)) { for (;;) { final HttpData d = data.poll(); if (d == null || !res.tryWrite(d)) { break; logger.warn("{} Failed to produce a response:", ctx, t); } finally { res.close(); res.close();
/** * Writes the HTTP response of the specified {@link HttpStatus} and closes the stream if the * {@link HttpStatusClass} is not {@linkplain HttpStatusClass#INFORMATIONAL informational} (1xx). * * @deprecated Use {@link HttpResponse#of(HttpStatus)}. */ @Deprecated default void respond(HttpStatus status) { requireNonNull(status, "status"); if (status.codeClass() == HttpStatusClass.INFORMATIONAL) { write(HttpHeaders.of(status)); } else if (isContentAlwaysEmpty(status)) { write(HttpHeaders.of(status)); close(); } else { respond(status, MediaType.PLAIN_TEXT_UTF_8, status.toHttpData()); } }
/** * Writes the specified HTTP response and closes the stream. * * @deprecated Use {@link #close(AggregatedHttpMessage)}. */ @Deprecated default void respond(AggregatedHttpMessage res) { close(res); }
private void doSendMessage(O message) { checkState(sendHeadersCalled, "sendHeaders has not been called"); checkState(!closeCalled, "call is closed"); if (firstResponse == null) { firstResponse = message; } try { res.write(messageFramer.writePayload(marshaller.serializeResponse(message))); res.onDemand(() -> { if (pendingMessagesUpdater.decrementAndGet(this) == 0) { if (useBlockingTaskExecutor) { ctx.blockingTaskExecutor().execute(this::invokeOnReady); } else { invokeOnReady(); } } }); } catch (RuntimeException e) { close(Status.fromThrowable(e), EMPTY_METADATA); throw e; } catch (Throwable t) { close(Status.fromThrowable(t), EMPTY_METADATA); throw new RuntimeException(t); } }
@Override protected final HttpResponse doRead(HttpHeaders headers, long length, Executor fileReadExecutor, ByteBufAllocator alloc) throws IOException { final T in = newStream(); if (in == null) { return null; } boolean submitted = false; try { final HttpResponseWriter res = HttpResponse.streaming(); res.write(headers); fileReadExecutor.execute(() -> doRead(res, in, 0, length, fileReadExecutor, alloc)); submitted = true; return res; } finally { if (!submitted) { close(in); } } }
this.advertisedEncodingsHeader = advertisedEncodingsHeader; res.completionFuture().handleAsync((unused, t) -> { if (!closeCalled) {
@Override public void run() { s.request(1); writer.onDemand(this); } });
/** * Creates a new failed HTTP response. */ static HttpResponse ofFailure(Throwable cause) { final HttpResponseWriter res = streaming(); res.close(cause); return res; }
private void doSendMessage(O message) { checkState(sendHeadersCalled, "sendHeaders has not been called"); checkState(!closeCalled, "call is closed"); if (firstResponse == null) { firstResponse = message; } try { res.write(messageFramer.writePayload(marshaller.serializeResponse(message))); res.onDemand(() -> { if (pendingMessagesUpdater.decrementAndGet(this) == 0) { if (useBlockingTaskExecutor) { ctx.blockingTaskExecutor().execute(this::invokeOnReady); } else { invokeOnReady(); } } }); } catch (RuntimeException e) { close(Status.fromThrowable(e), EMPTY_METADATA); throw e; } catch (Throwable t) { close(Status.fromThrowable(t), EMPTY_METADATA); throw new RuntimeException(t); } }
private void doSendHeaders(Metadata unusedGrpcMetadata) { checkState(!sendHeadersCalled, "sendHeaders already called"); checkState(!closeCalled, "call is closed"); final HttpHeaders headers = HttpHeaders.of(HttpStatus.OK); headers.contentType(serializationFormat.mediaType()); if (compressor == null || !messageCompression || clientAcceptEncoding == null) { compressor = Codec.Identity.NONE; } else { final List<String> acceptedEncodingsList = ACCEPT_ENCODING_SPLITTER.splitToList(clientAcceptEncoding); if (!acceptedEncodingsList.contains(compressor.getMessageEncoding())) { // resort to using no compression. compressor = Codec.Identity.NONE; } } messageFramer.setCompressor(compressor); // Always put compressor, even if it's identity. headers.add(GrpcHeaderNames.GRPC_ENCODING, compressor.getMessageEncoding()); if (!advertisedEncodingsHeader.isEmpty()) { headers.add(GrpcHeaderNames.GRPC_ACCEPT_ENCODING, advertisedEncodingsHeader); } sendHeadersCalled = true; res.write(headers); }
@Before public void setUp() { completionFuture = new CompletableFuture<>(); when(res.completionFuture()).thenReturn(completionFuture); ctx = ServiceRequestContextBuilder.of(HttpRequest.of(HttpMethod.POST, "/")) .eventLoop(eventLoop.get()) .build(); call = new ArmeriaServerCall<>( HttpHeaders.of(), TestServiceGrpc.getUnaryCallMethod(), CompressorRegistry.getDefaultInstance(), DecompressorRegistry.getDefaultInstance(), res, MAX_MESSAGE_BYTES, MAX_MESSAGE_BYTES, ctx, GrpcSerializationFormats.PROTO, MessageMarshaller.builder().build(), false, false, "gzip"); call.setListener(listener); call.messageReader().onSubscribe(subscription); ctx.attr(GrpcUnsafeBufferUtil.BUFFERS).set(buffersAttr); }