package runtime

import (
	
	
	
	
	
	
	
	

	
	
	
	
	
)

// ForwardResponseStream forwards the stream from gRPC server to REST client.
func ( context.Context,  *ServeMux,  Marshaler,  http.ResponseWriter,  *http.Request,  func() (proto.Message, error),  ...func(context.Context, http.ResponseWriter, proto.Message) error) {
	 := http.NewResponseController()
	,  := ServerMetadataFromContext()
	if ! {
		grpclog.Error("Failed to extract ServerMetadata from context")
		http.Error(, "unexpected error", http.StatusInternalServerError)
		return
	}
	handleForwardResponseServerMetadata(, , )

	.Header().Set("Transfer-Encoding", "chunked")
	if  := handleForwardResponseOptions(, , nil, );  != nil {
		HTTPError(, , , , , )
		return
	}

	var  []byte
	if ,  := .(Delimited);  {
		 = .Delimiter()
	} else {
		 = []byte("\n")
	}

	var  bool
	for {
		,  := ()
		if errors.Is(, io.EOF) {
			return
		}
		if  != nil {
			handleForwardResponseStreamError(, , , , , , , )
			return
		}
		if  := handleForwardResponseOptions(, , , );  != nil {
			handleForwardResponseStreamError(, , , , , , , )
			return
		}

		,  := .forwardResponseRewriter(, )
		if  != nil {
			grpclog.Errorf("Rewrite error: %v", )
			handleForwardResponseStreamError(, , , , , , , )
			return
		}

		if ! {
			var  string
			if ,  := .(StreamContentType);  {
				 = .StreamContentType()
			} else {
				 = .ContentType()
			}
			.Header().Set("Content-Type", )
		}

		var  []byte
		,  := .(*httpbody.HttpBody)
		switch {
		case  == nil:
			,  = .Marshal(errorChunk(status.New(codes.Internal, "empty response")))
		case :
			 = .GetData()
		default:
			 := map[string]interface{}{"result": }
			if ,  := .(responseBody);  {
				["result"] = .XXX_ResponseBody()
			}

			,  = .Marshal()
		}

		if  != nil {
			grpclog.Errorf("Failed to marshal response chunk: %v", )
			handleForwardResponseStreamError(, , , , , , , )
			return
		}
		if ,  := .Write();  != nil {
			grpclog.Errorf("Failed to send response chunk: %v", )
			return
		}
		 = true
		if ,  := .Write();  != nil {
			grpclog.Errorf("Failed to send delimiter chunk: %v", )
			return
		}
		 = .Flush()
		if  != nil {
			if errors.Is(, http.ErrNotSupported) {
				grpclog.Errorf("Flush not supported in %T", )
				http.Error(, "unexpected type of web server", http.StatusInternalServerError)
				return
			}
			grpclog.Errorf("Failed to flush response to client: %v", )
			return
		}
	}
}

func handleForwardResponseServerMetadata( http.ResponseWriter,  *ServeMux,  ServerMetadata) {
	for ,  := range .HeaderMD {
		if ,  := .outgoingHeaderMatcher();  {
			for ,  := range  {
				.Header().Add(, )
			}
		}
	}
}

func handleForwardResponseTrailerHeader( http.ResponseWriter,  *ServeMux,  ServerMetadata) {
	for  := range .TrailerMD {
		if ,  := .outgoingTrailerMatcher();  {
			.Header().Add("Trailer", textproto.CanonicalMIMEHeaderKey())
		}
	}
}

func handleForwardResponseTrailer( http.ResponseWriter,  *ServeMux,  ServerMetadata) {
	for ,  := range .TrailerMD {
		if ,  := .outgoingTrailerMatcher();  {
			for ,  := range  {
				.Header().Add(, )
			}
		}
	}
}

// responseBody interface contains method for getting field for marshaling to the response body
// this method is generated for response struct from the value of `response_body` in the `google.api.HttpRule`
type responseBody interface {
	XXX_ResponseBody() interface{}
}

// ForwardResponseMessage forwards the message "resp" from gRPC server to REST client.
func ( context.Context,  *ServeMux,  Marshaler,  http.ResponseWriter,  *http.Request,  proto.Message,  ...func(context.Context, http.ResponseWriter, proto.Message) error) {
	,  := ServerMetadataFromContext()
	if  {
		handleForwardResponseServerMetadata(, , )
	}

	// RFC 7230 https://tools.ietf.org/html/rfc7230#section-4.1.2
	// Unless the request includes a TE header field indicating "trailers"
	// is acceptable, as described in Section 4.3, a server SHOULD NOT
	// generate trailer fields that it believes are necessary for the user
	// agent to receive.
	 := requestAcceptsTrailers()

	if  &&  {
		handleForwardResponseTrailerHeader(, , )
		.Header().Set("Transfer-Encoding", "chunked")
	}

	 := .ContentType()
	.Header().Set("Content-Type", )

	if  := handleForwardResponseOptions(, , , );  != nil {
		HTTPError(, , , , , )
		return
	}
	,  := .forwardResponseRewriter(, )
	if  != nil {
		grpclog.Errorf("Rewrite error: %v", )
		HTTPError(, , , , , )
		return
	}
	var  []byte
	if ,  := .(responseBody);  {
		,  = .Marshal(.XXX_ResponseBody())
	} else {
		,  = .Marshal()
	}
	if  != nil {
		grpclog.Errorf("Marshal error: %v", )
		HTTPError(, , , , , )
		return
	}

	if ! && .writeContentLength {
		.Header().Set("Content-Length", strconv.Itoa(len()))
	}

	if _,  = .Write();  != nil && !errors.Is(, http.ErrBodyNotAllowed) {
		grpclog.Errorf("Failed to write response: %v", )
	}

	if  &&  {
		handleForwardResponseTrailer(, , )
	}
}

func requestAcceptsTrailers( *http.Request) bool {
	 := .Header.Get("TE")
	return strings.Contains(strings.ToLower(), "trailers")
}

func handleForwardResponseOptions( context.Context,  http.ResponseWriter,  proto.Message,  []func(context.Context, http.ResponseWriter, proto.Message) error) error {
	if len() == 0 {
		return nil
	}
	for ,  := range  {
		if  := (, , );  != nil {
			return fmt.Errorf("error handling ForwardResponseOptions: %w", )
		}
	}
	return nil
}

func handleForwardResponseStreamError( context.Context,  bool,  Marshaler,  http.ResponseWriter,  *http.Request,  *ServeMux,  error,  []byte) {
	 := .streamErrorHandler(, )
	 := errorChunk()
	if ! {
		.Header().Set("Content-Type", .ContentType())
		.WriteHeader(HTTPStatusFromCode(.Code()))
	}
	,  := .Marshal()
	if  != nil {
		grpclog.Errorf("Failed to marshal an error: %v", )
		return
	}
	if ,  := .Write();  != nil {
		grpclog.Errorf("Failed to notify error to client: %v", )
		return
	}
	if ,  := .Write();  != nil {
		grpclog.Errorf("Failed to send delimiter chunk: %v", )
		return
	}
}

func errorChunk( *status.Status) map[string]proto.Message {
	return map[string]proto.Message{"error": .Proto()}
}