-
Notifications
You must be signed in to change notification settings - Fork 35
/
request_message_translator.h
178 lines (149 loc) · 6.48 KB
/
request_message_translator.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
/* Copyright 2016 Google Inc. All Rights Reserved.
*
* 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.
*/
#ifndef GRPC_TRANSCODING_REQUEST_MESSAGE_TRANSLATOR_H_
#define GRPC_TRANSCODING_REQUEST_MESSAGE_TRANSLATOR_H_
#include <memory>
#include <string>
#include "absl/strings/string_view.h"
#include "google/protobuf/stubs/bytestream.h"
#include "google/protobuf/type.pb.h"
#include "google/protobuf/util/converter/error_listener.h"
#include "google/protobuf/util/converter/protostream_objectwriter.h"
#include "google/protobuf/util/type_resolver.h"
#include "message_stream.h"
#include "prefix_writer.h"
#include "request_weaver.h"
namespace google {
namespace grpc {
namespace transcoding {
// RequestInfo contains the information needed for request translation.
struct RequestInfo {
// The protobuf type that we are translating to.
const google::protobuf::Type* message_type;
// body_field_path is a dot-delimited chain of protobuf field names that
// defines the (potentially nested) location in the message, where the
// translated HTTP body must be inserted. E.g. "shelf.theme" means that the
// translated HTTP body must be inserted into the "theme" field of the "shelf"
// field of the request message.
std::string body_field_path;
// A collection of variable bindings extracted from the HTTP url or other
// sources that must be injected into certain fields of the translated
// message.
std::vector<RequestWeaver::BindingInfo> variable_bindings;
// Whether to reject the request if the binding value and the body value
// are conflicted.
bool reject_binding_body_field_collisions = false;
// Proto enum values are supposed to be all in upper cases.
// If true, enum values can be in lower cases.
bool case_insensitive_enum_parsing = false;
};
// RequestMessageTranslator translates ObjectWriter events into a single
// protobuf message. The protobuf message is built based on the input
// ObjectWriter events and a RequestInfo.
// If output_delimiter is true, RequestMessageTranslator will prepend the output
// message with a GRPC message delimiter - a 1-byte compression flag and a
// 4-byte message length (see http://www.grpc.io/docs/guides/wire.html).
// The translated message is exposed through MessageStream interface.
//
// The implementation uses a pipeline of ObjectWriters to do the job:
// PrefixWriter -> RequestWeaver -> ProtoStreamObjectWriter
//
// - PrefixWriter writes the body prefix making sure that the body goes to the
// right place and forwards the writer events to the RequestWeaver. This link
// will be absent if the prefix is empty.
// - RequestWeaver injects the variable bindings and forwards the writer events
// to the ProtoStreamObjectWriter. This link will be absent if there are no
// variable bindings to weave.
// - ProtoStreamObjectWriter does the actual proto writing.
//
// Example:
// RequestMessageTranslator t(type_resolver, true, std::move(request_info));
//
// ObjectWriter& input = t.Input();
//
// input.StartObject("");
// ...
// write the request body using input ObjectWriter
// ...
// input.EndObject();
//
// if (!t.Status().ok()) {
// printf("Error: %s\n", t->Status().ErrorMessage().as_string().c_str());
// return;
// }
//
// std::string message;
// if (t.NextMessage(&message)) {
// printf("Message=%s\n", message.c_str());
// }
//
class RequestMessageTranslator : public MessageStream {
public:
// type_resolver is forwarded to the ProtoStreamObjectWriter that does the
// actual proto writing.
// output_delimiter specifies whether to output the GRPC 5 byte message
// delimiter before the message or not.
RequestMessageTranslator(google::protobuf::util::TypeResolver& type_resolver,
bool output_delimiter, RequestInfo request_info);
~RequestMessageTranslator();
// An ObjectWriter that takes the input object to translate
google::protobuf::util::converter::ObjectWriter& Input() {
return *writer_pipeline_;
}
// MessageStream methods
bool NextMessage(std::string* message);
bool Finished() const;
absl::Status Status() const { return error_listener_.status(); }
private:
// Reserves space (5 bytes) for the GRPC delimiter to be written later. As it
// requires the length of the message, we can't write it before the message
// itself.
void ReserveDelimiterSpace();
// Writes the wire delimiter into the reserved delimiter space at the begining
// of this->message_.
void WriteDelimiter();
// The message being written
std::string message_;
// StringByteSink instance that appends the bytes to this->message_. We pass
// this to the ProtoStreamObjectWriter for writing the translated message.
google::protobuf::strings::StringByteSink sink_;
// ErrorListener implementation that converts the error events into
// a status.
StatusErrorListener error_listener_;
// The proto writer for writing the actual proto bytes
google::protobuf::util::converter::ProtoStreamObjectWriter proto_writer_;
// A RequestWeaver for writing the variable bindings
std::unique_ptr<RequestWeaver> request_weaver_;
// A PrefixWriter for writing the body prefix
std::unique_ptr<PrefixWriter> prefix_writer_;
// The ObjectWriter that will receive the events
// This is either &proto_writer_, request_weaver_.get() or
// prefix_writer_.get()
google::protobuf::util::converter::ObjectWriter* writer_pipeline_;
// Whether to ouput a delimiter before the message or not
bool output_delimiter_;
// A flag that indicates whether the message has been already read or not
// This helps with the MessageStream implementation.
bool finished_;
// GRPC delimiter size = 1 + 4 - 1-byte compression flag and 4-byte message
// length.
static const int kDelimiterSize = 5;
RequestMessageTranslator(const RequestMessageTranslator&) = delete;
RequestMessageTranslator& operator=(const RequestMessageTranslator&) = delete;
};
} // namespace transcoding
} // namespace grpc
} // namespace google
#endif // GRPC_TRANSCODING_REQUEST_MESSAGE_TRANSLATOR_H_