|  | @@ -63,21 +63,31 @@ class CallHook;
 | 
	
		
			
				|  |  |  class CompletionQueue;
 | 
	
		
			
				|  |  |  extern CoreCodegenInterface* g_core_codegen_interface;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +const char kBinaryErrorDetailsKey[] = "grpc-status-details-bin";
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  // TODO(yangg) if the map is changed before we send, the pointers will be a
 | 
	
		
			
				|  |  |  // mess. Make sure it does not happen.
 | 
	
		
			
				|  |  |  inline grpc_metadata* FillMetadataArray(
 | 
	
		
			
				|  |  | -    const std::multimap<grpc::string, grpc::string>& metadata) {
 | 
	
		
			
				|  |  | -  if (metadata.empty()) {
 | 
	
		
			
				|  |  | +    const std::multimap<grpc::string, grpc::string>& metadata,
 | 
	
		
			
				|  |  | +    size_t* metadata_count, const grpc::string& optional_error_details) {
 | 
	
		
			
				|  |  | +  *metadata_count = metadata.size() + (optional_error_details.empty() ? 0 : 1);
 | 
	
		
			
				|  |  | +  if (*metadata_count == 0) {
 | 
	
		
			
				|  |  |      return nullptr;
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |    grpc_metadata* metadata_array =
 | 
	
		
			
				|  |  |        (grpc_metadata*)(g_core_codegen_interface->gpr_malloc(
 | 
	
		
			
				|  |  | -          metadata.size() * sizeof(grpc_metadata)));
 | 
	
		
			
				|  |  | +          (*metadata_count) * sizeof(grpc_metadata)));
 | 
	
		
			
				|  |  |    size_t i = 0;
 | 
	
		
			
				|  |  |    for (auto iter = metadata.cbegin(); iter != metadata.cend(); ++iter, ++i) {
 | 
	
		
			
				|  |  |      metadata_array[i].key = SliceReferencingString(iter->first);
 | 
	
		
			
				|  |  |      metadata_array[i].value = SliceReferencingString(iter->second);
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  | +  if (!optional_error_details.empty()) {
 | 
	
		
			
				|  |  | +    metadata_array[i].key =
 | 
	
		
			
				|  |  | +        g_core_codegen_interface->grpc_slice_from_static_buffer(
 | 
	
		
			
				|  |  | +            kBinaryErrorDetailsKey, sizeof(kBinaryErrorDetailsKey) - 1);
 | 
	
		
			
				|  |  | +    metadata_array[i].value = SliceReferencingString(optional_error_details);
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  |    return metadata_array;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -216,8 +226,8 @@ class CallOpSendInitialMetadata {
 | 
	
		
			
				|  |  |      maybe_compression_level_.is_set = false;
 | 
	
		
			
				|  |  |      send_ = true;
 | 
	
		
			
				|  |  |      flags_ = flags;
 | 
	
		
			
				|  |  | -    initial_metadata_count_ = metadata.size();
 | 
	
		
			
				|  |  | -    initial_metadata_ = FillMetadataArray(metadata);
 | 
	
		
			
				|  |  | +    initial_metadata_ =
 | 
	
		
			
				|  |  | +        FillMetadataArray(metadata, &initial_metadata_count_, "");
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    void set_compression_level(grpc_compression_level level) {
 | 
	
	
		
			
				|  | @@ -454,11 +464,12 @@ class CallOpServerSendStatus {
 | 
	
		
			
				|  |  |    void ServerSendStatus(
 | 
	
		
			
				|  |  |        const std::multimap<grpc::string, grpc::string>& trailing_metadata,
 | 
	
		
			
				|  |  |        const Status& status) {
 | 
	
		
			
				|  |  | -    trailing_metadata_count_ = trailing_metadata.size();
 | 
	
		
			
				|  |  | -    trailing_metadata_ = FillMetadataArray(trailing_metadata);
 | 
	
		
			
				|  |  | +    send_error_details_ = status.error_details();
 | 
	
		
			
				|  |  | +    trailing_metadata_ = FillMetadataArray(
 | 
	
		
			
				|  |  | +        trailing_metadata, &trailing_metadata_count_, send_error_details_);
 | 
	
		
			
				|  |  |      send_status_available_ = true;
 | 
	
		
			
				|  |  |      send_status_code_ = static_cast<grpc_status_code>(GetCanonicalCode(status));
 | 
	
		
			
				|  |  | -    send_status_details_ = status.error_message();
 | 
	
		
			
				|  |  | +    send_error_message_ = status.error_message();
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |   protected:
 | 
	
	
		
			
				|  | @@ -470,9 +481,9 @@ class CallOpServerSendStatus {
 | 
	
		
			
				|  |  |          trailing_metadata_count_;
 | 
	
		
			
				|  |  |      op->data.send_status_from_server.trailing_metadata = trailing_metadata_;
 | 
	
		
			
				|  |  |      op->data.send_status_from_server.status = send_status_code_;
 | 
	
		
			
				|  |  | -    status_details_slice_ = SliceReferencingString(send_status_details_);
 | 
	
		
			
				|  |  | +    error_message_slice_ = SliceReferencingString(send_error_message_);
 | 
	
		
			
				|  |  |      op->data.send_status_from_server.status_details =
 | 
	
		
			
				|  |  | -        send_status_details_.empty() ? nullptr : &status_details_slice_;
 | 
	
		
			
				|  |  | +        send_error_message_.empty() ? nullptr : &error_message_slice_;
 | 
	
		
			
				|  |  |      op->flags = 0;
 | 
	
		
			
				|  |  |      op->reserved = NULL;
 | 
	
		
			
				|  |  |    }
 | 
	
	
		
			
				|  | @@ -486,10 +497,11 @@ class CallOpServerSendStatus {
 | 
	
		
			
				|  |  |   private:
 | 
	
		
			
				|  |  |    bool send_status_available_;
 | 
	
		
			
				|  |  |    grpc_status_code send_status_code_;
 | 
	
		
			
				|  |  | -  grpc::string send_status_details_;
 | 
	
		
			
				|  |  | +  grpc::string send_error_details_;
 | 
	
		
			
				|  |  | +  grpc::string send_error_message_;
 | 
	
		
			
				|  |  |    size_t trailing_metadata_count_;
 | 
	
		
			
				|  |  |    grpc_metadata* trailing_metadata_;
 | 
	
		
			
				|  |  | -  grpc_slice status_details_slice_;
 | 
	
		
			
				|  |  | +  grpc_slice error_message_slice_;
 | 
	
		
			
				|  |  |  };
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  class CallOpRecvInitialMetadata {
 | 
	
	
		
			
				|  | @@ -528,7 +540,7 @@ class CallOpClientRecvStatus {
 | 
	
		
			
				|  |  |    void ClientRecvStatus(ClientContext* context, Status* status) {
 | 
	
		
			
				|  |  |      metadata_map_ = &context->trailing_metadata_;
 | 
	
		
			
				|  |  |      recv_status_ = status;
 | 
	
		
			
				|  |  | -    status_details_ = g_core_codegen_interface->grpc_empty_slice();
 | 
	
		
			
				|  |  | +    error_message_ = g_core_codegen_interface->grpc_empty_slice();
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |   protected:
 | 
	
	
		
			
				|  | @@ -538,7 +550,7 @@ class CallOpClientRecvStatus {
 | 
	
		
			
				|  |  |      op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
 | 
	
		
			
				|  |  |      op->data.recv_status_on_client.trailing_metadata = metadata_map_->arr();
 | 
	
		
			
				|  |  |      op->data.recv_status_on_client.status = &status_code_;
 | 
	
		
			
				|  |  | -    op->data.recv_status_on_client.status_details = &status_details_;
 | 
	
		
			
				|  |  | +    op->data.recv_status_on_client.status_details = &error_message_;
 | 
	
		
			
				|  |  |      op->flags = 0;
 | 
	
		
			
				|  |  |      op->reserved = NULL;
 | 
	
		
			
				|  |  |    }
 | 
	
	
		
			
				|  | @@ -546,10 +558,17 @@ class CallOpClientRecvStatus {
 | 
	
		
			
				|  |  |    void FinishOp(bool* status) {
 | 
	
		
			
				|  |  |      if (recv_status_ == nullptr) return;
 | 
	
		
			
				|  |  |      metadata_map_->FillMap();
 | 
	
		
			
				|  |  | +    grpc::string binary_error_details;
 | 
	
		
			
				|  |  | +    auto iter = metadata_map_->map()->find(kBinaryErrorDetailsKey);
 | 
	
		
			
				|  |  | +    if (iter != metadata_map_->map()->end()) {
 | 
	
		
			
				|  |  | +      binary_error_details =
 | 
	
		
			
				|  |  | +          grpc::string(iter->second.begin(), iter->second.length());
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  |      *recv_status_ = Status(static_cast<StatusCode>(status_code_),
 | 
	
		
			
				|  |  | -                           grpc::string(GRPC_SLICE_START_PTR(status_details_),
 | 
	
		
			
				|  |  | -                                        GRPC_SLICE_END_PTR(status_details_)));
 | 
	
		
			
				|  |  | -    g_core_codegen_interface->grpc_slice_unref(status_details_);
 | 
	
		
			
				|  |  | +                           grpc::string(GRPC_SLICE_START_PTR(error_message_),
 | 
	
		
			
				|  |  | +                                        GRPC_SLICE_END_PTR(error_message_)),
 | 
	
		
			
				|  |  | +                           binary_error_details);
 | 
	
		
			
				|  |  | +    g_core_codegen_interface->grpc_slice_unref(error_message_);
 | 
	
		
			
				|  |  |      recv_status_ = nullptr;
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -557,7 +576,7 @@ class CallOpClientRecvStatus {
 | 
	
		
			
				|  |  |    MetadataMap* metadata_map_;
 | 
	
		
			
				|  |  |    Status* recv_status_;
 | 
	
		
			
				|  |  |    grpc_status_code status_code_;
 | 
	
		
			
				|  |  | -  grpc_slice status_details_;
 | 
	
		
			
				|  |  | +  grpc_slice error_message_;
 | 
	
		
			
				|  |  |  };
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  /// An abstract collection of CallOpSet's, to be used whenever
 |