/*
 * Copyright 2018 Netflix, Inc.
 *
 *      Licensed under the Apache License, Version 2.0 (the "License");
 *      you may not use this file except in compliance with the License.
 *      You may obtain a copy of the License at
 *
 *          http://www.apache.org/licenses/LICENSE-2.0
 *
 *      Unless required by applicable law or agreed to in writing, software
 *      distributed under the License is distributed on an "AS IS" BASIS,
 *      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *      See the License for the specific language governing permissions and
 *      limitations under the License.
 */

package com.netflix.zuul.filters.http;

import com.netflix.zuul.filters.SyncEndpoint;
import com.netflix.zuul.message.ZuulMessage;
import com.netflix.zuul.message.http.HttpRequestMessage;
import com.netflix.zuul.message.http.HttpResponseMessage;
import com.netflix.zuul.message.http.HttpResponseMessageImpl;

/**
 * User: Mike Smith
 * Date: 6/16/15
 * Time: 12:23 AM
 */
public abstract class HttpSyncEndpoint extends SyncEndpoint<HttpRequestMessage, HttpResponseMessage>
{
    @Override
    public HttpResponseMessage getDefaultOutput(HttpRequestMessage request)
    {
        return HttpResponseMessageImpl.defaultErrorResponse(request);
    }
}

@@ -676,16 +676,72 @@
 .http;%0A%0A
+import com.netflix.config.CachedDynamicBooleanProperty;%0A
 import c
@@ -764,20 +764,16 @@
 filters.
-Sync
 Endpoint
@@ -774,16 +774,64 @@
 dpoint;%0A
+import com.netflix.zuul.filters.SyncZuulFilter;%0A
 import c
@@ -1043,16 +1043,160 @@
 ageImpl;
+%0Aimport io.netty.handler.codec.http.HttpContent;%0Aimport io.netty.handler.codec.http.LastHttpContent;%0Aimport rx.Observable;%0Aimport rx.Subscriber;
 %0A%0A/**%0A *
@@ -1299,20 +1299,16 @@
 extends 
-Sync
 Endpoint
@@ -1352,174 +1352,1793 @@
 age%3E
-%0A%7B%0A    @Override%0A    public HttpResponseMessage getDefaultOutput(HttpRequestMessage request)%0A    %7B%0A        return HttpResponseMessageImpl.defaultErrorResponse(request
+ implements SyncZuulFilter%3CHttpRequestMessage, HttpResponseMessage%3E%0A%7B%0A    // Feature flag for enabling this while we get some real data for the impact.%0A    private static final CachedDynamicBooleanProperty WAIT_FOR_LASTCONTENT = new CachedDynamicBooleanProperty(%22zuul.endpoint.sync.wait_for_lastcontent%22, true);%0A%0A    private ZuulMessage response = null;%0A    private Subscriber subscriber = null;%0A%0A    @Override%0A    public HttpResponseMessage getDefaultOutput(HttpRequestMessage request)%0A    %7B%0A        return HttpResponseMessageImpl.defaultErrorResponse(request);%0A    %7D%0A%0A    @Override%0A    public Observable%3CHttpResponseMessage%3E applyAsync(HttpRequestMessage input)%0A    %7B%0A        if (WAIT_FOR_LASTCONTENT.get() && ! input.hasCompleteBody()) %7B%0A            // Return an observable that won't complete until after we have received the LastContent from client (ie. that we've%0A            // received the whole request body), so that we can't potentially corrupt the clients' http state on this connection.%0A            return Observable.create(subscriber -%3E %7B%0A                this.response = this.apply(input);%0A                this.subscriber = subscriber;%0A            %7D);%0A        %7D%0A        else %7B%0A            return Observable.just(this.apply(input));%0A        %7D%0A    %7D%0A%0A    @Override%0A    public HttpContent processContentChunk(ZuulMessage zuulMessage, HttpContent chunk)%0A    %7B%0A        // Only call onNext() after we've received the LastContent of request from client.%0A        if (chunk instanceof LastHttpContent) %7B%0A            if (subscriber != null) %7B%0A                subscriber.onNext(response);%0A                subscriber.onCompleted();%0A                response = null;%0A                subscriber = null;%0A            %7D%0A        %7D%0A        return super.processContentChunk(zuulMessage, chunk
 );%0A 

Change HttpSyncEndpoint to not respond until we've received the LastContent of the request