Repository: grpc/grpc-go
File: internal/transport/http2_client.go (Go)

Code before:
		}
	}

	//if not a gRPC response - evaluate entire http status and process close stream / response
	//for 200 -> Unknown, else decode the error
	if !isGRPC {
		var grpcErrorCode = codes.Internal // when header does not include HTTP status, return INTERNAL
		var errs []string

		switch receivedHTTPStatus {
		case "":
			httpStatusErr = "malformed header: missing HTTP status"
		case "200":
			grpcErrorCode = codes.Unknown
		default:
			// Any other status code (e.g., "404", "503"). We must parse it.
			c, err := strconv.ParseInt(receivedHTTPStatus, 10, 32)
			if err != nil {
				se := status.New(grpcErrorCode, fmt.Sprintf("transport: malformed http-status: %v", err))
				t.closeStream(s, se.Err(), true, http2.ErrCodeProtocol, se, nil, endStream)
				return
			}
			statusCode := int(c)
			if statusCode >= 100 && statusCode < 200 {
				//In case of informational headers return
				//For trailers, since we are already in gRPC mode, we will ignore all http statuses and not enter this block
				return
			}
			httpStatusErr = fmt.Sprintf(
				"unexpected HTTP status code received from server: %d (%s)",
				statusCode,
				http.StatusText(statusCode),
			)
			var ok bool
			grpcErrorCode, ok = HTTPStatusConvTab[statusCode]
			if !ok {
				grpcErrorCode = codes.Unknown
			}

		}

		if httpStatusErr != "" {
			errs = append(errs, httpStatusErr)
		}

		if contentTypeErr != "" {
			errs = append(errs, contentTypeErr)
		}
		// Verify the HTTP response is a 200.
		se := status.New(grpcErrorCode, strings.Join(errs, "; "))
		t.closeStream(s, se.Err(), true, http2.ErrCodeProtocol, se, nil, endStream)

Review comment (suggestion):
It looks like the check for the `endStream` flag was removed.
https://github.com/grpc/grpc-go/blob/8420f3ff9ce4617369e054cedb51fda6d45c3340/internal/transport/http2_client.go#L1521-L1528

Code after:
			grpcMessage = decodeGrpcMessage(hf.Value)
		case ":status":
			httpStatus = hf.Value
		default:
			if isReservedHeader(hf.Name) && !isWhitelistedHeader(hf.Name) {
				break
			}
			v, err := decodeMetadataHeader(hf.Name, hf.Value)
			if err != nil {
				headerError = fmt.Sprintf("transport: malformed %s: %v", hf.Name, err)
				logger.Warningf("Failed to decode metadata header (%q, %q): %v", hf.Name, hf.Value, err)
				break
			}
			mdata[hf.Name] = append(mdata[hf.Name], v)
		}
	}

	// If a non-gRPC response is received, then evaluate the HTTP status to
	// process the response and close the stream.
	// In case http status doesn't provide any error information (status : 200),
	// then evalute response code to be Unknown.
	if !isGRPC {
		var grpcErrorCode = codes.Internal
		if httpStatus == "" {
			httpStatusErr = "malformed header: missing HTTP status"
		} else {
			// Parse the status codes (e.g. "200", 404").
			statusCode, err := strconv.Atoi(httpStatus)
			if err != nil {
				se := status.New(grpcErrorCode, fmt.Sprintf("transport: malformed http-status: %v", err))
				t.closeStream(s, se.Err(), true, http2.ErrCodeProtocol, se, nil, endStream)
				return
			}
			if statusCode >= 100 && statusCode < 200 {
				if endStream {
					se := status.New(codes.Internal, fmt.Sprintf(
						"protocol error: informational header with status code %d must not have END_STREAM set", statusCode))
					t.closeStream(s, se.Err(), true, http2.ErrCodeProtocol, se, nil, endStream)
				}
				// In case of informational headers, return.
				return
			}
			httpStatusErr = fmt.Sprintf(
				"unexpected HTTP status code received from server: %d (%s)",
				statusCode,
				http.StatusText(statusCode),
			)
			var ok bool
			grpcErrorCode, ok = HTTPStatusConvTab[statusCode]
			if !ok {
				grpcErrorCode = codes.Unknown