|  | @@ -44,7 +44,9 @@
 | 
	
		
			
				|  |  |  #include <grpc/support/string_util.h>
 | 
	
		
			
				|  |  |  #include <grpc/support/useful.h>
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +#include "src/core/ext/transport/chttp2/transport/http2_errors.h"
 | 
	
		
			
				|  |  |  #include "src/core/ext/transport/chttp2/transport/internal.h"
 | 
	
		
			
				|  |  | +#include "src/core/ext/transport/chttp2/transport/status_conversion.h"
 | 
	
		
			
				|  |  |  #include "src/core/ext/transport/chttp2/transport/varint.h"
 | 
	
		
			
				|  |  |  #include "src/core/lib/channel/channel_args.h"
 | 
	
		
			
				|  |  |  #include "src/core/lib/http/parser.h"
 | 
	
	
		
			
				|  | @@ -53,10 +55,7 @@
 | 
	
		
			
				|  |  |  #include "src/core/lib/slice/slice_internal.h"
 | 
	
		
			
				|  |  |  #include "src/core/lib/slice/slice_string_helpers.h"
 | 
	
		
			
				|  |  |  #include "src/core/lib/support/string.h"
 | 
	
		
			
				|  |  | -#include "src/core/lib/transport/error_utils.h"
 | 
	
		
			
				|  |  | -#include "src/core/lib/transport/http2_errors.h"
 | 
	
		
			
				|  |  |  #include "src/core/lib/transport/static_metadata.h"
 | 
	
		
			
				|  |  | -#include "src/core/lib/transport/status_conversion.h"
 | 
	
		
			
				|  |  |  #include "src/core/lib/transport/timeout_encoding.h"
 | 
	
		
			
				|  |  |  #include "src/core/lib/transport/transport_impl.h"
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -410,7 +409,7 @@ static void close_transport_locked(grpc_exec_ctx *exec_ctx,
 | 
	
		
			
				|  |  |            grpc_error_add_child(t->close_transport_on_writes_finished, error);
 | 
	
		
			
				|  |  |        return;
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  | -    if (!grpc_error_has_clear_grpc_status(error)) {
 | 
	
		
			
				|  |  | +    if (!grpc_error_get_int(error, GRPC_ERROR_INT_GRPC_STATUS, NULL)) {
 | 
	
		
			
				|  |  |        error = grpc_error_set_int(error, GRPC_ERROR_INT_GRPC_STATUS,
 | 
	
		
			
				|  |  |                                   GRPC_STATUS_UNAVAILABLE);
 | 
	
		
			
				|  |  |      }
 | 
	
	
		
			
				|  | @@ -867,6 +866,7 @@ void grpc_chttp2_complete_closure_step(grpc_exec_ctx *exec_ctx,
 | 
	
		
			
				|  |  |              (int)(closure->next_data.scratch / CLOSURE_BARRIER_FIRST_REF_BIT),
 | 
	
		
			
				|  |  |              (int)(closure->next_data.scratch % CLOSURE_BARRIER_FIRST_REF_BIT),
 | 
	
		
			
				|  |  |              desc, errstr);
 | 
	
		
			
				|  |  | +    grpc_error_free_string(errstr);
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |    if (error != GRPC_ERROR_NONE) {
 | 
	
		
			
				|  |  |      if (closure->error_data.error == GRPC_ERROR_NONE) {
 | 
	
	
		
			
				|  | @@ -895,9 +895,12 @@ void grpc_chttp2_complete_closure_step(grpc_exec_ctx *exec_ctx,
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  static bool contains_non_ok_status(grpc_metadata_batch *batch) {
 | 
	
		
			
				|  |  | -  if (batch->idx.named.grpc_status != NULL) {
 | 
	
		
			
				|  |  | -    return !grpc_mdelem_eq(batch->idx.named.grpc_status->md,
 | 
	
		
			
				|  |  | -                           GRPC_MDELEM_GRPC_STATUS_0);
 | 
	
		
			
				|  |  | +  grpc_linked_mdelem *l;
 | 
	
		
			
				|  |  | +  for (l = batch->list.head; l; l = l->next) {
 | 
	
		
			
				|  |  | +    if (l->md->key == GRPC_MDSTR_GRPC_STATUS &&
 | 
	
		
			
				|  |  | +        l->md != GRPC_MDELEM_GRPC_STATUS_0) {
 | 
	
		
			
				|  |  | +      return true;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |    return false;
 | 
	
		
			
				|  |  |  }
 | 
	
	
		
			
				|  | @@ -977,12 +980,9 @@ static void log_metadata(const grpc_metadata_batch *md_batch, uint32_t id,
 | 
	
		
			
				|  |  |                           bool is_client, bool is_initial) {
 | 
	
		
			
				|  |  |    for (grpc_linked_mdelem *md = md_batch->list.head; md != md_batch->list.tail;
 | 
	
		
			
				|  |  |         md = md->next) {
 | 
	
		
			
				|  |  | -    char *key = grpc_slice_to_c_string(GRPC_MDKEY(md->md));
 | 
	
		
			
				|  |  | -    char *value = grpc_slice_to_c_string(GRPC_MDVALUE(md->md));
 | 
	
		
			
				|  |  |      gpr_log(GPR_INFO, "HTTP:%d:%s:%s: %s: %s", id, is_initial ? "HDR" : "TRL",
 | 
	
		
			
				|  |  | -            is_client ? "CLI" : "SVR", key, value);
 | 
	
		
			
				|  |  | -    gpr_free(key);
 | 
	
		
			
				|  |  | -    gpr_free(value);
 | 
	
		
			
				|  |  | +            is_client ? "CLI" : "SVR", grpc_mdstr_as_c_string(md->md->key),
 | 
	
		
			
				|  |  | +            grpc_mdstr_as_c_string(md->md->value));
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -1025,7 +1025,11 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx, void *stream_op,
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    if (op->cancel_error != GRPC_ERROR_NONE) {
 | 
	
		
			
				|  |  | -    grpc_chttp2_cancel_stream(exec_ctx, t, s, op->cancel_error);
 | 
	
		
			
				|  |  | +    grpc_chttp2_cancel_stream(exec_ctx, t, s, GRPC_ERROR_REF(op->cancel_error));
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  if (op->close_error != GRPC_ERROR_NONE) {
 | 
	
		
			
				|  |  | +    close_from_api(exec_ctx, t, s, GRPC_ERROR_REF(op->close_error));
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    if (op->send_initial_metadata != NULL) {
 | 
	
	
		
			
				|  | @@ -1076,9 +1080,8 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx, void *stream_op,
 | 
	
		
			
				|  |  |          s->send_initial_metadata = NULL;
 | 
	
		
			
				|  |  |          grpc_chttp2_complete_closure_step(
 | 
	
		
			
				|  |  |              exec_ctx, t, s, &s->send_initial_metadata_finished,
 | 
	
		
			
				|  |  | -            GRPC_ERROR_CREATE_REFERENCING(
 | 
	
		
			
				|  |  | -                "Attempt to send initial metadata after stream was closed",
 | 
	
		
			
				|  |  | -                &s->write_closed_error, 1),
 | 
	
		
			
				|  |  | +            GRPC_ERROR_CREATE(
 | 
	
		
			
				|  |  | +                "Attempt to send initial metadata after stream was closed"),
 | 
	
		
			
				|  |  |              "send_initial_metadata_finished");
 | 
	
		
			
				|  |  |        }
 | 
	
		
			
				|  |  |      }
 | 
	
	
		
			
				|  | @@ -1090,9 +1093,7 @@ static void perform_stream_op_locked(grpc_exec_ctx *exec_ctx, void *stream_op,
 | 
	
		
			
				|  |  |      if (s->write_closed) {
 | 
	
		
			
				|  |  |        grpc_chttp2_complete_closure_step(
 | 
	
		
			
				|  |  |            exec_ctx, t, s, &s->fetching_send_message_finished,
 | 
	
		
			
				|  |  | -          GRPC_ERROR_CREATE_REFERENCING(
 | 
	
		
			
				|  |  | -              "Attempt to send message after stream was closed",
 | 
	
		
			
				|  |  | -              &s->write_closed_error, 1),
 | 
	
		
			
				|  |  | +          GRPC_ERROR_CREATE("Attempt to send message after stream was closed"),
 | 
	
		
			
				|  |  |            "fetching_send_message_finished");
 | 
	
		
			
				|  |  |      } else {
 | 
	
		
			
				|  |  |        GPR_ASSERT(s->fetching_send_message == NULL);
 | 
	
	
		
			
				|  | @@ -1264,16 +1265,11 @@ void grpc_chttp2_ack_ping(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  static void send_goaway(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
 | 
	
		
			
				|  |  | -                        grpc_error *error) {
 | 
	
		
			
				|  |  | +                        grpc_chttp2_error_code error, grpc_slice data) {
 | 
	
		
			
				|  |  |    t->sent_goaway_state = GRPC_CHTTP2_GOAWAY_SEND_SCHEDULED;
 | 
	
		
			
				|  |  | -  grpc_http2_error_code http_error;
 | 
	
		
			
				|  |  | -  const char *msg;
 | 
	
		
			
				|  |  | -  grpc_error_get_status(error, gpr_inf_future(GPR_CLOCK_MONOTONIC), NULL, &msg,
 | 
	
		
			
				|  |  | -                        &http_error);
 | 
	
		
			
				|  |  | -  grpc_chttp2_goaway_append(t->last_new_stream_id, (uint32_t)http_error,
 | 
	
		
			
				|  |  | -                            grpc_slice_from_copied_string(msg), &t->qbuf);
 | 
	
		
			
				|  |  | +  grpc_chttp2_goaway_append(t->last_new_stream_id, (uint32_t)error, data,
 | 
	
		
			
				|  |  | +                            &t->qbuf);
 | 
	
		
			
				|  |  |    grpc_chttp2_initiate_write(exec_ctx, t, false, "goaway_sent");
 | 
	
		
			
				|  |  | -  GRPC_ERROR_UNREF(error);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  static void perform_transport_op_locked(grpc_exec_ctx *exec_ctx,
 | 
	
	
		
			
				|  | @@ -1289,8 +1285,10 @@ static void perform_transport_op_locked(grpc_exec_ctx *exec_ctx,
 | 
	
		
			
				|  |  |          op->on_connectivity_state_change);
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  if (op->goaway_error) {
 | 
	
		
			
				|  |  | -    send_goaway(exec_ctx, t, op->goaway_error);
 | 
	
		
			
				|  |  | +  if (op->send_goaway) {
 | 
	
		
			
				|  |  | +    send_goaway(exec_ctx, t,
 | 
	
		
			
				|  |  | +                grpc_chttp2_grpc_status_to_http2_error(op->goaway_status),
 | 
	
		
			
				|  |  | +                grpc_slice_ref_internal(*op->goaway_message));
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    if (op->set_accept_stream) {
 | 
	
	
		
			
				|  | @@ -1350,8 +1348,8 @@ void grpc_chttp2_maybe_complete_recv_initial_metadata(grpc_exec_ctx *exec_ctx,
 | 
	
		
			
				|  |  |          incoming_byte_stream_destroy_locked(exec_ctx, bs, GRPC_ERROR_NONE);
 | 
	
		
			
				|  |  |        }
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  | -    grpc_chttp2_incoming_metadata_buffer_publish(
 | 
	
		
			
				|  |  | -        exec_ctx, &s->metadata_buffer[0], s->recv_initial_metadata);
 | 
	
		
			
				|  |  | +    grpc_chttp2_incoming_metadata_buffer_publish(&s->metadata_buffer[0],
 | 
	
		
			
				|  |  | +                                                 s->recv_initial_metadata);
 | 
	
		
			
				|  |  |      null_then_run_closure(exec_ctx, &s->recv_initial_metadata_ready,
 | 
	
		
			
				|  |  |                            GRPC_ERROR_NONE);
 | 
	
		
			
				|  |  |    }
 | 
	
	
		
			
				|  | @@ -1394,8 +1392,8 @@ void grpc_chttp2_maybe_complete_recv_trailing_metadata(grpc_exec_ctx *exec_ctx,
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |      if (s->all_incoming_byte_streams_finished &&
 | 
	
		
			
				|  |  |          s->recv_trailing_metadata_finished != NULL) {
 | 
	
		
			
				|  |  | -      grpc_chttp2_incoming_metadata_buffer_publish(
 | 
	
		
			
				|  |  | -          exec_ctx, &s->metadata_buffer[1], s->recv_trailing_metadata);
 | 
	
		
			
				|  |  | +      grpc_chttp2_incoming_metadata_buffer_publish(&s->metadata_buffer[1],
 | 
	
		
			
				|  |  | +                                                   s->recv_trailing_metadata);
 | 
	
		
			
				|  |  |        grpc_chttp2_complete_closure_step(
 | 
	
		
			
				|  |  |            exec_ctx, t, s, &s->recv_trailing_metadata_finished, GRPC_ERROR_NONE,
 | 
	
		
			
				|  |  |            "recv_trailing_metadata_finished");
 | 
	
	
		
			
				|  | @@ -1443,37 +1441,70 @@ static void remove_stream(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
 | 
	
		
			
				|  |  |    maybe_start_some_streams(exec_ctx, t);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +static void status_codes_from_error(grpc_error *error, gpr_timespec deadline,
 | 
	
		
			
				|  |  | +                                    grpc_chttp2_error_code *http2_error,
 | 
	
		
			
				|  |  | +                                    grpc_status_code *grpc_status) {
 | 
	
		
			
				|  |  | +  intptr_t ip_http;
 | 
	
		
			
				|  |  | +  intptr_t ip_grpc;
 | 
	
		
			
				|  |  | +  bool have_http =
 | 
	
		
			
				|  |  | +      grpc_error_get_int(error, GRPC_ERROR_INT_HTTP2_ERROR, &ip_http);
 | 
	
		
			
				|  |  | +  bool have_grpc =
 | 
	
		
			
				|  |  | +      grpc_error_get_int(error, GRPC_ERROR_INT_GRPC_STATUS, &ip_grpc);
 | 
	
		
			
				|  |  | +  if (have_http) {
 | 
	
		
			
				|  |  | +    *http2_error = (grpc_chttp2_error_code)ip_http;
 | 
	
		
			
				|  |  | +  } else if (have_grpc) {
 | 
	
		
			
				|  |  | +    *http2_error =
 | 
	
		
			
				|  |  | +        grpc_chttp2_grpc_status_to_http2_error((grpc_status_code)ip_grpc);
 | 
	
		
			
				|  |  | +  } else {
 | 
	
		
			
				|  |  | +    *http2_error = GRPC_CHTTP2_INTERNAL_ERROR;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  if (have_grpc) {
 | 
	
		
			
				|  |  | +    *grpc_status = (grpc_status_code)ip_grpc;
 | 
	
		
			
				|  |  | +  } else if (have_http) {
 | 
	
		
			
				|  |  | +    *grpc_status = grpc_chttp2_http2_error_to_grpc_status(
 | 
	
		
			
				|  |  | +        (grpc_chttp2_error_code)ip_http, deadline);
 | 
	
		
			
				|  |  | +  } else {
 | 
	
		
			
				|  |  | +    *grpc_status = GRPC_STATUS_INTERNAL;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  void grpc_chttp2_cancel_stream(grpc_exec_ctx *exec_ctx,
 | 
	
		
			
				|  |  |                                 grpc_chttp2_transport *t, grpc_chttp2_stream *s,
 | 
	
		
			
				|  |  |                                 grpc_error *due_to_error) {
 | 
	
		
			
				|  |  | -  if (!t->is_client && !s->sent_trailing_metadata &&
 | 
	
		
			
				|  |  | -      grpc_error_has_clear_grpc_status(due_to_error)) {
 | 
	
		
			
				|  |  | -    close_from_api(exec_ctx, t, s, due_to_error);
 | 
	
		
			
				|  |  | -    return;
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |    if (!s->read_closed || !s->write_closed) {
 | 
	
		
			
				|  |  | +    grpc_status_code grpc_status;
 | 
	
		
			
				|  |  | +    grpc_chttp2_error_code http_error;
 | 
	
		
			
				|  |  | +    status_codes_from_error(due_to_error, s->deadline, &http_error,
 | 
	
		
			
				|  |  | +                            &grpc_status);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |      if (s->id != 0) {
 | 
	
		
			
				|  |  | -      grpc_http2_error_code http_error;
 | 
	
		
			
				|  |  | -      grpc_error_get_status(due_to_error, s->deadline, NULL, NULL, &http_error);
 | 
	
		
			
				|  |  |        grpc_slice_buffer_add(
 | 
	
		
			
				|  |  |            &t->qbuf, grpc_chttp2_rst_stream_create(s->id, (uint32_t)http_error,
 | 
	
		
			
				|  |  |                                                    &s->stats.outgoing));
 | 
	
		
			
				|  |  |        grpc_chttp2_initiate_write(exec_ctx, t, false, "rst_stream");
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    const char *msg =
 | 
	
		
			
				|  |  | +        grpc_error_get_str(due_to_error, GRPC_ERROR_STR_GRPC_MESSAGE);
 | 
	
		
			
				|  |  | +    bool free_msg = false;
 | 
	
		
			
				|  |  | +    if (msg == NULL) {
 | 
	
		
			
				|  |  | +      free_msg = true;
 | 
	
		
			
				|  |  | +      msg = grpc_error_string(due_to_error);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    grpc_slice msg_slice = grpc_slice_from_copied_string(msg);
 | 
	
		
			
				|  |  | +    grpc_chttp2_fake_status(exec_ctx, t, s, grpc_status, &msg_slice);
 | 
	
		
			
				|  |  | +    if (free_msg) grpc_error_free_string(msg);
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |    if (due_to_error != GRPC_ERROR_NONE && !s->seen_error) {
 | 
	
		
			
				|  |  |      s->seen_error = true;
 | 
	
		
			
				|  |  | +    grpc_chttp2_maybe_complete_recv_trailing_metadata(exec_ctx, t, s);
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |    grpc_chttp2_mark_stream_closed(exec_ctx, t, s, 1, 1, due_to_error);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  void grpc_chttp2_fake_status(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
 | 
	
		
			
				|  |  | -                             grpc_chttp2_stream *s, grpc_error *error) {
 | 
	
		
			
				|  |  | -  grpc_status_code status;
 | 
	
		
			
				|  |  | -  const char *msg;
 | 
	
		
			
				|  |  | -  grpc_error_get_status(error, s->deadline, &status, &msg, NULL);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | +                             grpc_chttp2_stream *s, grpc_status_code status,
 | 
	
		
			
				|  |  | +                             grpc_slice *slice) {
 | 
	
		
			
				|  |  |    if (status != GRPC_STATUS_OK) {
 | 
	
		
			
				|  |  |      s->seen_error = true;
 | 
	
		
			
				|  |  |    }
 | 
	
	
		
			
				|  | @@ -1487,21 +1518,24 @@ void grpc_chttp2_fake_status(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
 | 
	
		
			
				|  |  |        s->recv_trailing_metadata_finished != NULL) {
 | 
	
		
			
				|  |  |      char status_string[GPR_LTOA_MIN_BUFSIZE];
 | 
	
		
			
				|  |  |      gpr_ltoa(status, status_string);
 | 
	
		
			
				|  |  | -    grpc_chttp2_incoming_metadata_buffer_replace_or_add(
 | 
	
		
			
				|  |  | -        exec_ctx, &s->metadata_buffer[1],
 | 
	
		
			
				|  |  | -        grpc_mdelem_from_slices(exec_ctx, GRPC_MDSTR_GRPC_STATUS,
 | 
	
		
			
				|  |  | -                                grpc_slice_from_copied_string(status_string)));
 | 
	
		
			
				|  |  | -    if (msg != NULL) {
 | 
	
		
			
				|  |  | -      grpc_chttp2_incoming_metadata_buffer_replace_or_add(
 | 
	
		
			
				|  |  | -          exec_ctx, &s->metadata_buffer[1],
 | 
	
		
			
				|  |  | -          grpc_mdelem_from_slices(exec_ctx, GRPC_MDSTR_GRPC_MESSAGE,
 | 
	
		
			
				|  |  | -                                  grpc_slice_from_copied_string(msg)));
 | 
	
		
			
				|  |  | +    grpc_chttp2_incoming_metadata_buffer_add(
 | 
	
		
			
				|  |  | +        &s->metadata_buffer[1], grpc_mdelem_from_metadata_strings(
 | 
	
		
			
				|  |  | +                                    exec_ctx, GRPC_MDSTR_GRPC_STATUS,
 | 
	
		
			
				|  |  | +                                    grpc_mdstr_from_string(status_string)));
 | 
	
		
			
				|  |  | +    if (slice) {
 | 
	
		
			
				|  |  | +      grpc_chttp2_incoming_metadata_buffer_add(
 | 
	
		
			
				|  |  | +          &s->metadata_buffer[1],
 | 
	
		
			
				|  |  | +          grpc_mdelem_from_metadata_strings(
 | 
	
		
			
				|  |  | +              exec_ctx, GRPC_MDSTR_GRPC_MESSAGE,
 | 
	
		
			
				|  |  | +              grpc_mdstr_from_slice(exec_ctx,
 | 
	
		
			
				|  |  | +                                    grpc_slice_ref_internal(*slice))));
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |      s->published_metadata[1] = GRPC_METADATA_SYNTHESIZED_FROM_FAKE;
 | 
	
		
			
				|  |  |      grpc_chttp2_maybe_complete_recv_trailing_metadata(exec_ctx, t, s);
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  GRPC_ERROR_UNREF(error);
 | 
	
		
			
				|  |  | +  if (slice) {
 | 
	
		
			
				|  |  | +    grpc_slice_unref_internal(exec_ctx, *slice);
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  static void add_error(grpc_error *error, grpc_error **refs, size_t *nrefs) {
 | 
	
	
		
			
				|  | @@ -1567,48 +1601,36 @@ void grpc_chttp2_mark_stream_closed(grpc_exec_ctx *exec_ctx,
 | 
	
		
			
				|  |  |                                      int close_writes, grpc_error *error) {
 | 
	
		
			
				|  |  |    if (s->read_closed && s->write_closed) {
 | 
	
		
			
				|  |  |      /* already closed */
 | 
	
		
			
				|  |  | -    grpc_chttp2_maybe_complete_recv_trailing_metadata(exec_ctx, t, s);
 | 
	
		
			
				|  |  |      GRPC_ERROR_UNREF(error);
 | 
	
		
			
				|  |  |      return;
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  | -  bool closed_read = false;
 | 
	
		
			
				|  |  | -  bool became_closed = false;
 | 
	
		
			
				|  |  |    if (close_reads && !s->read_closed) {
 | 
	
		
			
				|  |  |      s->read_closed_error = GRPC_ERROR_REF(error);
 | 
	
		
			
				|  |  |      s->read_closed = true;
 | 
	
		
			
				|  |  | -    closed_read = true;
 | 
	
		
			
				|  |  | +    for (int i = 0; i < 2; i++) {
 | 
	
		
			
				|  |  | +      if (s->published_metadata[i] == GRPC_METADATA_NOT_PUBLISHED) {
 | 
	
		
			
				|  |  | +        s->published_metadata[i] = GPRC_METADATA_PUBLISHED_AT_CLOSE;
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    decrement_active_streams_locked(exec_ctx, t, s);
 | 
	
		
			
				|  |  | +    grpc_chttp2_maybe_complete_recv_initial_metadata(exec_ctx, t, s);
 | 
	
		
			
				|  |  | +    grpc_chttp2_maybe_complete_recv_message(exec_ctx, t, s);
 | 
	
		
			
				|  |  | +    grpc_chttp2_maybe_complete_recv_trailing_metadata(exec_ctx, t, s);
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |    if (close_writes && !s->write_closed) {
 | 
	
		
			
				|  |  |      s->write_closed_error = GRPC_ERROR_REF(error);
 | 
	
		
			
				|  |  |      s->write_closed = true;
 | 
	
		
			
				|  |  |      grpc_chttp2_fail_pending_writes(exec_ctx, t, s, GRPC_ERROR_REF(error));
 | 
	
		
			
				|  |  | +    grpc_chttp2_maybe_complete_recv_trailing_metadata(exec_ctx, t, s);
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |    if (s->read_closed && s->write_closed) {
 | 
	
		
			
				|  |  | -    became_closed = true;
 | 
	
		
			
				|  |  | -    grpc_error *overall_error =
 | 
	
		
			
				|  |  | -        removal_error(GRPC_ERROR_REF(error), s, "Stream removed");
 | 
	
		
			
				|  |  |      if (s->id != 0) {
 | 
	
		
			
				|  |  | -      remove_stream(exec_ctx, t, s->id, GRPC_ERROR_REF(overall_error));
 | 
	
		
			
				|  |  | +      remove_stream(exec_ctx, t, s->id,
 | 
	
		
			
				|  |  | +                    removal_error(GRPC_ERROR_REF(error), s, "Stream removed"));
 | 
	
		
			
				|  |  |      } else {
 | 
	
		
			
				|  |  |        /* Purge streams waiting on concurrency still waiting for id assignment */
 | 
	
		
			
				|  |  |        grpc_chttp2_list_remove_waiting_for_concurrency(t, s);
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  | -    if (overall_error != GRPC_ERROR_NONE) {
 | 
	
		
			
				|  |  | -      grpc_chttp2_fake_status(exec_ctx, t, s, overall_error);
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -  if (closed_read) {
 | 
	
		
			
				|  |  | -    for (int i = 0; i < 2; i++) {
 | 
	
		
			
				|  |  | -      if (s->published_metadata[i] == GRPC_METADATA_NOT_PUBLISHED) {
 | 
	
		
			
				|  |  | -        s->published_metadata[i] = GPRC_METADATA_PUBLISHED_AT_CLOSE;
 | 
	
		
			
				|  |  | -      }
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -    decrement_active_streams_locked(exec_ctx, t, s);
 | 
	
		
			
				|  |  | -    grpc_chttp2_maybe_complete_recv_initial_metadata(exec_ctx, t, s);
 | 
	
		
			
				|  |  | -    grpc_chttp2_maybe_complete_recv_message(exec_ctx, t, s);
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -  if (became_closed) {
 | 
	
		
			
				|  |  | -    grpc_chttp2_maybe_complete_recv_trailing_metadata(exec_ctx, t, s);
 | 
	
		
			
				|  |  |      GRPC_CHTTP2_STREAM_UNREF(exec_ctx, s, "chttp2");
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |    GRPC_ERROR_UNREF(error);
 | 
	
	
		
			
				|  | @@ -1622,92 +1644,112 @@ static void close_from_api(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
 | 
	
		
			
				|  |  |    uint8_t *p;
 | 
	
		
			
				|  |  |    uint32_t len = 0;
 | 
	
		
			
				|  |  |    grpc_status_code grpc_status;
 | 
	
		
			
				|  |  | -  const char *msg;
 | 
	
		
			
				|  |  | -  grpc_error_get_status(error, s->deadline, &grpc_status, &msg, NULL);
 | 
	
		
			
				|  |  | +  grpc_chttp2_error_code http_error;
 | 
	
		
			
				|  |  | +  status_codes_from_error(error, s->deadline, &http_error, &grpc_status);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    GPR_ASSERT(grpc_status >= 0 && (int)grpc_status < 100);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  /* Hand roll a header block.
 | 
	
		
			
				|  |  | -     This is unnecessarily ugly - at some point we should find a more
 | 
	
		
			
				|  |  | -     elegant solution.
 | 
	
		
			
				|  |  | -     It's complicated by the fact that our send machinery would be dead by
 | 
	
		
			
				|  |  | -     the time we got around to sending this, so instead we ignore HPACK
 | 
	
		
			
				|  |  | -     compression and just write the uncompressed bytes onto the wire. */
 | 
	
		
			
				|  |  | -  status_hdr = grpc_slice_malloc(15 + (grpc_status >= 10));
 | 
	
		
			
				|  |  | -  p = GRPC_SLICE_START_PTR(status_hdr);
 | 
	
		
			
				|  |  | -  *p++ = 0x00; /* literal header, not indexed */
 | 
	
		
			
				|  |  | -  *p++ = 11;   /* len(grpc-status) */
 | 
	
		
			
				|  |  | -  *p++ = 'g';
 | 
	
		
			
				|  |  | -  *p++ = 'r';
 | 
	
		
			
				|  |  | -  *p++ = 'p';
 | 
	
		
			
				|  |  | -  *p++ = 'c';
 | 
	
		
			
				|  |  | -  *p++ = '-';
 | 
	
		
			
				|  |  | -  *p++ = 's';
 | 
	
		
			
				|  |  | -  *p++ = 't';
 | 
	
		
			
				|  |  | -  *p++ = 'a';
 | 
	
		
			
				|  |  | -  *p++ = 't';
 | 
	
		
			
				|  |  | -  *p++ = 'u';
 | 
	
		
			
				|  |  | -  *p++ = 's';
 | 
	
		
			
				|  |  | -  if (grpc_status < 10) {
 | 
	
		
			
				|  |  | -    *p++ = 1;
 | 
	
		
			
				|  |  | -    *p++ = (uint8_t)('0' + grpc_status);
 | 
	
		
			
				|  |  | -  } else {
 | 
	
		
			
				|  |  | -    *p++ = 2;
 | 
	
		
			
				|  |  | -    *p++ = (uint8_t)('0' + (grpc_status / 10));
 | 
	
		
			
				|  |  | -    *p++ = (uint8_t)('0' + (grpc_status % 10));
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -  GPR_ASSERT(p == GRPC_SLICE_END_PTR(status_hdr));
 | 
	
		
			
				|  |  | -  len += (uint32_t)GRPC_SLICE_LENGTH(status_hdr);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  if (msg != NULL) {
 | 
	
		
			
				|  |  | -    size_t msg_len = strlen(msg);
 | 
	
		
			
				|  |  | -    GPR_ASSERT(msg_len <= UINT32_MAX);
 | 
	
		
			
				|  |  | -    uint32_t msg_len_len = GRPC_CHTTP2_VARINT_LENGTH((uint32_t)msg_len, 0);
 | 
	
		
			
				|  |  | -    message_pfx = grpc_slice_malloc(14 + msg_len_len);
 | 
	
		
			
				|  |  | -    p = GRPC_SLICE_START_PTR(message_pfx);
 | 
	
		
			
				|  |  | -    *p++ = 0x00; /* literal header, not indexed */
 | 
	
		
			
				|  |  | -    *p++ = 12;   /* len(grpc-message) */
 | 
	
		
			
				|  |  | +  if (s->id != 0 && !t->is_client) {
 | 
	
		
			
				|  |  | +    /* Hand roll a header block.
 | 
	
		
			
				|  |  | +       This is unnecessarily ugly - at some point we should find a more
 | 
	
		
			
				|  |  | +       elegant
 | 
	
		
			
				|  |  | +       solution.
 | 
	
		
			
				|  |  | +       It's complicated by the fact that our send machinery would be dead by
 | 
	
		
			
				|  |  | +       the
 | 
	
		
			
				|  |  | +       time we got around to sending this, so instead we ignore HPACK
 | 
	
		
			
				|  |  | +       compression
 | 
	
		
			
				|  |  | +       and just write the uncompressed bytes onto the wire. */
 | 
	
		
			
				|  |  | +    status_hdr = grpc_slice_malloc(15 + (grpc_status >= 10));
 | 
	
		
			
				|  |  | +    p = GRPC_SLICE_START_PTR(status_hdr);
 | 
	
		
			
				|  |  | +    *p++ = 0x40; /* literal header */
 | 
	
		
			
				|  |  | +    *p++ = 11;   /* len(grpc-status) */
 | 
	
		
			
				|  |  |      *p++ = 'g';
 | 
	
		
			
				|  |  |      *p++ = 'r';
 | 
	
		
			
				|  |  |      *p++ = 'p';
 | 
	
		
			
				|  |  |      *p++ = 'c';
 | 
	
		
			
				|  |  |      *p++ = '-';
 | 
	
		
			
				|  |  | -    *p++ = 'm';
 | 
	
		
			
				|  |  | -    *p++ = 'e';
 | 
	
		
			
				|  |  | -    *p++ = 's';
 | 
	
		
			
				|  |  |      *p++ = 's';
 | 
	
		
			
				|  |  | +    *p++ = 't';
 | 
	
		
			
				|  |  |      *p++ = 'a';
 | 
	
		
			
				|  |  | -    *p++ = 'g';
 | 
	
		
			
				|  |  | -    *p++ = 'e';
 | 
	
		
			
				|  |  | -    GRPC_CHTTP2_WRITE_VARINT((uint32_t)msg_len, 0, 0, p, (uint32_t)msg_len_len);
 | 
	
		
			
				|  |  | -    p += msg_len_len;
 | 
	
		
			
				|  |  | -    GPR_ASSERT(p == GRPC_SLICE_END_PTR(message_pfx));
 | 
	
		
			
				|  |  | -    len += (uint32_t)GRPC_SLICE_LENGTH(message_pfx);
 | 
	
		
			
				|  |  | -    len += (uint32_t)msg_len;
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  hdr = grpc_slice_malloc(9);
 | 
	
		
			
				|  |  | -  p = GRPC_SLICE_START_PTR(hdr);
 | 
	
		
			
				|  |  | -  *p++ = (uint8_t)(len >> 16);
 | 
	
		
			
				|  |  | -  *p++ = (uint8_t)(len >> 8);
 | 
	
		
			
				|  |  | -  *p++ = (uint8_t)(len);
 | 
	
		
			
				|  |  | -  *p++ = GRPC_CHTTP2_FRAME_HEADER;
 | 
	
		
			
				|  |  | -  *p++ = GRPC_CHTTP2_DATA_FLAG_END_STREAM | GRPC_CHTTP2_DATA_FLAG_END_HEADERS;
 | 
	
		
			
				|  |  | -  *p++ = (uint8_t)(s->id >> 24);
 | 
	
		
			
				|  |  | -  *p++ = (uint8_t)(s->id >> 16);
 | 
	
		
			
				|  |  | -  *p++ = (uint8_t)(s->id >> 8);
 | 
	
		
			
				|  |  | -  *p++ = (uint8_t)(s->id);
 | 
	
		
			
				|  |  | -  GPR_ASSERT(p == GRPC_SLICE_END_PTR(hdr));
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  grpc_slice_buffer_add(&t->qbuf, hdr);
 | 
	
		
			
				|  |  | -  grpc_slice_buffer_add(&t->qbuf, status_hdr);
 | 
	
		
			
				|  |  | -  if (msg != NULL) {
 | 
	
		
			
				|  |  | -    grpc_slice_buffer_add(&t->qbuf, message_pfx);
 | 
	
		
			
				|  |  | -    grpc_slice_buffer_add(&t->qbuf, grpc_slice_from_copied_string(msg));
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -  grpc_slice_buffer_add(
 | 
	
		
			
				|  |  | -      &t->qbuf, grpc_chttp2_rst_stream_create(s->id, GRPC_HTTP2_NO_ERROR,
 | 
	
		
			
				|  |  | -                                              &s->stats.outgoing));
 | 
	
		
			
				|  |  | +    *p++ = 't';
 | 
	
		
			
				|  |  | +    *p++ = 'u';
 | 
	
		
			
				|  |  | +    *p++ = 's';
 | 
	
		
			
				|  |  | +    if (grpc_status < 10) {
 | 
	
		
			
				|  |  | +      *p++ = 1;
 | 
	
		
			
				|  |  | +      *p++ = (uint8_t)('0' + grpc_status);
 | 
	
		
			
				|  |  | +    } else {
 | 
	
		
			
				|  |  | +      *p++ = 2;
 | 
	
		
			
				|  |  | +      *p++ = (uint8_t)('0' + (grpc_status / 10));
 | 
	
		
			
				|  |  | +      *p++ = (uint8_t)('0' + (grpc_status % 10));
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    GPR_ASSERT(p == GRPC_SLICE_END_PTR(status_hdr));
 | 
	
		
			
				|  |  | +    len += (uint32_t)GRPC_SLICE_LENGTH(status_hdr);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    const char *optional_message =
 | 
	
		
			
				|  |  | +        grpc_error_get_str(error, GRPC_ERROR_STR_GRPC_MESSAGE);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    if (optional_message != NULL) {
 | 
	
		
			
				|  |  | +      size_t msg_len = strlen(optional_message);
 | 
	
		
			
				|  |  | +      GPR_ASSERT(msg_len <= UINT32_MAX);
 | 
	
		
			
				|  |  | +      uint32_t msg_len_len = GRPC_CHTTP2_VARINT_LENGTH((uint32_t)msg_len, 0);
 | 
	
		
			
				|  |  | +      message_pfx = grpc_slice_malloc(14 + msg_len_len);
 | 
	
		
			
				|  |  | +      p = GRPC_SLICE_START_PTR(message_pfx);
 | 
	
		
			
				|  |  | +      *p++ = 0x40;
 | 
	
		
			
				|  |  | +      *p++ = 12; /* len(grpc-message) */
 | 
	
		
			
				|  |  | +      *p++ = 'g';
 | 
	
		
			
				|  |  | +      *p++ = 'r';
 | 
	
		
			
				|  |  | +      *p++ = 'p';
 | 
	
		
			
				|  |  | +      *p++ = 'c';
 | 
	
		
			
				|  |  | +      *p++ = '-';
 | 
	
		
			
				|  |  | +      *p++ = 'm';
 | 
	
		
			
				|  |  | +      *p++ = 'e';
 | 
	
		
			
				|  |  | +      *p++ = 's';
 | 
	
		
			
				|  |  | +      *p++ = 's';
 | 
	
		
			
				|  |  | +      *p++ = 'a';
 | 
	
		
			
				|  |  | +      *p++ = 'g';
 | 
	
		
			
				|  |  | +      *p++ = 'e';
 | 
	
		
			
				|  |  | +      GRPC_CHTTP2_WRITE_VARINT((uint32_t)msg_len, 0, 0, p,
 | 
	
		
			
				|  |  | +                               (uint32_t)msg_len_len);
 | 
	
		
			
				|  |  | +      p += msg_len_len;
 | 
	
		
			
				|  |  | +      GPR_ASSERT(p == GRPC_SLICE_END_PTR(message_pfx));
 | 
	
		
			
				|  |  | +      len += (uint32_t)GRPC_SLICE_LENGTH(message_pfx);
 | 
	
		
			
				|  |  | +      len += (uint32_t)msg_len;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    hdr = grpc_slice_malloc(9);
 | 
	
		
			
				|  |  | +    p = GRPC_SLICE_START_PTR(hdr);
 | 
	
		
			
				|  |  | +    *p++ = (uint8_t)(len >> 16);
 | 
	
		
			
				|  |  | +    *p++ = (uint8_t)(len >> 8);
 | 
	
		
			
				|  |  | +    *p++ = (uint8_t)(len);
 | 
	
		
			
				|  |  | +    *p++ = GRPC_CHTTP2_FRAME_HEADER;
 | 
	
		
			
				|  |  | +    *p++ = GRPC_CHTTP2_DATA_FLAG_END_STREAM | GRPC_CHTTP2_DATA_FLAG_END_HEADERS;
 | 
	
		
			
				|  |  | +    *p++ = (uint8_t)(s->id >> 24);
 | 
	
		
			
				|  |  | +    *p++ = (uint8_t)(s->id >> 16);
 | 
	
		
			
				|  |  | +    *p++ = (uint8_t)(s->id >> 8);
 | 
	
		
			
				|  |  | +    *p++ = (uint8_t)(s->id);
 | 
	
		
			
				|  |  | +    GPR_ASSERT(p == GRPC_SLICE_END_PTR(hdr));
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    grpc_slice_buffer_add(&t->qbuf, hdr);
 | 
	
		
			
				|  |  | +    grpc_slice_buffer_add(&t->qbuf, status_hdr);
 | 
	
		
			
				|  |  | +    if (optional_message) {
 | 
	
		
			
				|  |  | +      grpc_slice_buffer_add(&t->qbuf, message_pfx);
 | 
	
		
			
				|  |  | +      grpc_slice_buffer_add(&t->qbuf,
 | 
	
		
			
				|  |  | +                            grpc_slice_from_copied_string(optional_message));
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    grpc_slice_buffer_add(
 | 
	
		
			
				|  |  | +        &t->qbuf, grpc_chttp2_rst_stream_create(s->id, GRPC_CHTTP2_NO_ERROR,
 | 
	
		
			
				|  |  | +                                                &s->stats.outgoing));
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  const char *msg = grpc_error_get_str(error, GRPC_ERROR_STR_GRPC_MESSAGE);
 | 
	
		
			
				|  |  | +  bool free_msg = false;
 | 
	
		
			
				|  |  | +  if (msg == NULL) {
 | 
	
		
			
				|  |  | +    free_msg = true;
 | 
	
		
			
				|  |  | +    msg = grpc_error_string(error);
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  grpc_slice msg_slice = grpc_slice_from_copied_string(msg);
 | 
	
		
			
				|  |  | +  grpc_chttp2_fake_status(exec_ctx, t, s, grpc_status, &msg_slice);
 | 
	
		
			
				|  |  | +  if (free_msg) grpc_error_free_string(msg);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    grpc_chttp2_mark_stream_closed(exec_ctx, t, s, 1, 1, error);
 | 
	
		
			
				|  |  |    grpc_chttp2_initiate_write(exec_ctx, t, false, "close_from_api");
 | 
	
	
		
			
				|  | @@ -1785,10 +1827,8 @@ static grpc_error *try_http_parsing(grpc_exec_ctx *exec_ctx,
 | 
	
		
			
				|  |  |    if (parse_error == GRPC_ERROR_NONE &&
 | 
	
		
			
				|  |  |        (parse_error = grpc_http_parser_eof(&parser)) == GRPC_ERROR_NONE) {
 | 
	
		
			
				|  |  |      error = grpc_error_set_int(
 | 
	
		
			
				|  |  | -        grpc_error_set_int(
 | 
	
		
			
				|  |  | -            GRPC_ERROR_CREATE("Trying to connect an http1.x server"),
 | 
	
		
			
				|  |  | -            GRPC_ERROR_INT_HTTP_STATUS, response.status),
 | 
	
		
			
				|  |  | -        GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE);
 | 
	
		
			
				|  |  | +        GRPC_ERROR_CREATE("Trying to connect an http1.x server"),
 | 
	
		
			
				|  |  | +        GRPC_ERROR_INT_HTTP_STATUS, response.status);
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |    GRPC_ERROR_UNREF(parse_error);
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -2049,8 +2089,6 @@ static void incoming_byte_stream_publish_error(
 | 
	
		
			
				|  |  |    grpc_closure_sched(exec_ctx, bs->on_next, GRPC_ERROR_REF(error));
 | 
	
		
			
				|  |  |    bs->on_next = NULL;
 | 
	
		
			
				|  |  |    GRPC_ERROR_UNREF(bs->error);
 | 
	
		
			
				|  |  | -  grpc_chttp2_cancel_stream(exec_ctx, bs->transport, bs->stream,
 | 
	
		
			
				|  |  | -                            GRPC_ERROR_REF(error));
 | 
	
		
			
				|  |  |    bs->error = error;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -2159,10 +2197,8 @@ static void benign_reclaimer_locked(grpc_exec_ctx *exec_ctx, void *arg,
 | 
	
		
			
				|  |  |        gpr_log(GPR_DEBUG, "HTTP2: %s - send goaway to free memory",
 | 
	
		
			
				|  |  |                t->peer_string);
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  | -    send_goaway(exec_ctx, t,
 | 
	
		
			
				|  |  | -                grpc_error_set_int(GRPC_ERROR_CREATE("Buffers full"),
 | 
	
		
			
				|  |  | -                                   GRPC_ERROR_INT_HTTP2_ERROR,
 | 
	
		
			
				|  |  | -                                   GRPC_HTTP2_ENHANCE_YOUR_CALM));
 | 
	
		
			
				|  |  | +    send_goaway(exec_ctx, t, GRPC_CHTTP2_ENHANCE_YOUR_CALM,
 | 
	
		
			
				|  |  | +                grpc_slice_from_static_string("Buffers full"));
 | 
	
		
			
				|  |  |    } else if (error == GRPC_ERROR_NONE && grpc_resource_quota_trace) {
 | 
	
		
			
				|  |  |      gpr_log(GPR_DEBUG,
 | 
	
		
			
				|  |  |              "HTTP2: %s - skip benign reclamation, there are still %" PRIdPTR
 | 
	
	
		
			
				|  | @@ -2191,7 +2227,7 @@ static void destructive_reclaimer_locked(grpc_exec_ctx *exec_ctx, void *arg,
 | 
	
		
			
				|  |  |      grpc_chttp2_cancel_stream(
 | 
	
		
			
				|  |  |          exec_ctx, t, s, grpc_error_set_int(GRPC_ERROR_CREATE("Buffers full"),
 | 
	
		
			
				|  |  |                                             GRPC_ERROR_INT_HTTP2_ERROR,
 | 
	
		
			
				|  |  | -                                           GRPC_HTTP2_ENHANCE_YOUR_CALM));
 | 
	
		
			
				|  |  | +                                           GRPC_CHTTP2_ENHANCE_YOUR_CALM));
 | 
	
		
			
				|  |  |      if (n > 1) {
 | 
	
		
			
				|  |  |        /* Since we cancel one stream per destructive reclamation, if
 | 
	
		
			
				|  |  |           there are more streams left, we can immediately post a new
 |