Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in / Register
Toggle navigation
B
brpc
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Packages
Packages
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
submodule
brpc
Commits
4a0927af
Commit
4a0927af
authored
Sep 28, 2018
by
gejun
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Fix many issues around impl. of grpc
parent
798e9a11
Hide whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
325 additions
and
356 deletions
+325
-356
client.cpp
example/grpc_c++/client.cpp
+4
-5
server.cpp
example/grpc_c++/server.cpp
+0
-1
http_message.cpp
src/brpc/details/http_message.cpp
+16
-14
http_message.h
src/brpc/details/http_message.h
+8
-8
global.cpp
src/brpc/global.cpp
+0
-12
grpc.cpp
src/brpc/grpc.cpp
+24
-0
grpc.h
src/brpc/grpc.h
+4
-1
http_header.h
src/brpc/http_header.h
+0
-2
options.proto
src/brpc/options.proto
+0
-1
http2_rpc_protocol.cpp
src/brpc/policy/http2_rpc_protocol.cpp
+15
-41
http2_rpc_protocol.h
src/brpc/policy/http2_rpc_protocol.h
+14
-5
http_rpc_protocol.cpp
src/brpc/policy/http_rpc_protocol.cpp
+232
-259
http_rpc_protocol.h
src/brpc/policy/http_rpc_protocol.h
+8
-7
No files found.
example/grpc_c++/client.cpp
View file @
4a0927af
...
@@ -21,7 +21,7 @@
...
@@ -21,7 +21,7 @@
#include <brpc/channel.h>
#include <brpc/channel.h>
#include "helloworld.pb.h"
#include "helloworld.pb.h"
DEFINE_string
(
protocol
,
"
grp
c"
,
"Protocol type. Defined in src/brpc/options.proto"
);
DEFINE_string
(
protocol
,
"
h2
c"
,
"Protocol type. Defined in src/brpc/options.proto"
);
DEFINE_string
(
server
,
"0.0.0.0:50051"
,
"IP Address of server"
);
DEFINE_string
(
server
,
"0.0.0.0:50051"
,
"IP Address of server"
);
DEFINE_string
(
load_balancer
,
""
,
"The algorithm for load balancing"
);
DEFINE_string
(
load_balancer
,
""
,
"The algorithm for load balancing"
);
DEFINE_int32
(
timeout_ms
,
100
,
"RPC timeout in milliseconds"
);
DEFINE_int32
(
timeout_ms
,
100
,
"RPC timeout in milliseconds"
);
...
@@ -59,22 +59,21 @@ int main(int argc, char* argv[]) {
...
@@ -59,22 +59,21 @@ int main(int argc, char* argv[]) {
helloworld
::
HelloReply
response
;
helloworld
::
HelloReply
response
;
brpc
::
Controller
cntl
;
brpc
::
Controller
cntl
;
request
.
set_name
(
"grpc client example"
);
request
.
set_name
(
"grpc_req_from_brpc"
);
cntl
.
http_request
().
set_content_type
(
"application/grpc"
);
if
(
FLAGS_gzip
)
{
if
(
FLAGS_gzip
)
{
cntl
.
set_request_compress_type
(
brpc
::
COMPRESS_TYPE_GZIP
);
cntl
.
set_request_compress_type
(
brpc
::
COMPRESS_TYPE_GZIP
);
}
}
// Because `done'(last parameter) is NULL, this function waits until
// Because `done'(last parameter) is NULL, this function waits until
// the response comes back or error occurs(including timedout).
// the response comes back or error occurs(including timedout).
stub
.
SayHello
(
&
cntl
,
&
request
,
&
response
,
NULL
);
stub
.
SayHello
(
&
cntl
,
&
request
,
&
response
,
NULL
);
//cntl.http_request().uri() = FLAGS_server;
//channel.CallMethod(NULL, &cntl, &request, &response, NULL);
if
(
!
cntl
.
Failed
())
{
if
(
!
cntl
.
Failed
())
{
LOG
(
INFO
)
<<
"Received response from "
<<
cntl
.
remote_side
()
LOG
(
INFO
)
<<
"Received response from "
<<
cntl
.
remote_side
()
<<
" to "
<<
cntl
.
local_side
()
<<
" to "
<<
cntl
.
local_side
()
<<
": "
<<
response
.
message
()
<<
": "
<<
response
.
message
()
<<
" latency="
<<
cntl
.
latency_us
()
<<
"us"
;
<<
" latency="
<<
cntl
.
latency_us
()
<<
"us"
;
}
else
{
}
else
{
LOG
(
WARNING
)
<<
cntl
.
Error
Code
()
<<
": "
<<
cntl
.
Error
Text
();
LOG
(
WARNING
)
<<
cntl
.
ErrorText
();
}
}
usleep
(
FLAGS_interval_ms
*
1000L
);
usleep
(
FLAGS_interval_ms
*
1000L
);
}
}
...
...
example/grpc_c++/server.cpp
View file @
4a0927af
...
@@ -42,7 +42,6 @@ public:
...
@@ -42,7 +42,6 @@ public:
if
(
FLAGS_gzip
)
{
if
(
FLAGS_gzip
)
{
cntl
->
set_response_compress_type
(
brpc
::
COMPRESS_TYPE_GZIP
);
cntl
->
set_response_compress_type
(
brpc
::
COMPRESS_TYPE_GZIP
);
}
}
LOG
(
INFO
)
<<
"req="
<<
req
->
name
();
res
->
set_message
(
"Hello "
+
req
->
name
());
res
->
set_message
(
"Hello "
+
req
->
name
());
// If an error happens, use controller::set_grpc_error_code to set errors
// If an error happens, use controller::set_grpc_error_code to set errors
// e.g., cntl->set_grpc_error_code(brpc::GRPC_RESOURCEEXHAUSTED, "test grpc message");
// e.g., cntl->set_grpc_error_code(brpc::GRPC_RESOURCEEXHAUSTED, "test grpc message");
...
...
src/brpc/details/http_message.cpp
View file @
4a0927af
...
@@ -225,12 +225,14 @@ int HttpMessage::OnBody(const char *at, const size_t length) {
...
@@ -225,12 +225,14 @@ int HttpMessage::OnBody(const char *at, const size_t length) {
delete
_vmsgbuilder
;
delete
_vmsgbuilder
;
_vmsgbuilder
=
NULL
;
_vmsgbuilder
=
NULL
;
}
else
{
}
else
{
if
(
_
body_length
<
(
size_t
)
FLAGS_http_verbose_max_body_length
)
{
if
(
_
vbodylen
<
(
size_t
)
FLAGS_http_verbose_max_body_length
)
{
int
plen
=
std
::
min
(
length
,
(
size_t
)
FLAGS_http_verbose_max_body_length
int
plen
=
std
::
min
(
length
,
(
size_t
)
FLAGS_http_verbose_max_body_length
-
_body_length
);
-
_vbodylen
);
_vmsgbuilder
->
write
(
at
,
plen
);
std
::
string
str
=
butil
::
ToPrintableString
(
at
,
plen
,
std
::
numeric_limits
<
size_t
>::
max
());
_vmsgbuilder
->
write
(
str
.
data
(),
str
.
size
());
}
}
_
body_length
+=
length
;
_
vbodylen
+=
length
;
}
}
}
}
if
(
_stage
!=
HTTP_ON_BODY
)
{
if
(
_stage
!=
HTTP_ON_BODY
)
{
...
@@ -280,8 +282,8 @@ int HttpMessage::OnBody(const char *at, const size_t length) {
...
@@ -280,8 +282,8 @@ int HttpMessage::OnBody(const char *at, const size_t length) {
int
HttpMessage
::
OnMessageComplete
()
{
int
HttpMessage
::
OnMessageComplete
()
{
if
(
_vmsgbuilder
)
{
if
(
_vmsgbuilder
)
{
if
(
_
body_length
>
(
size_t
)
FLAGS_http_verbose_max_body_length
)
{
if
(
_
vbodylen
>
(
size_t
)
FLAGS_http_verbose_max_body_length
)
{
*
_vmsgbuilder
<<
"
\n
<skipped "
<<
_
body_length
*
_vmsgbuilder
<<
"
\n
<skipped "
<<
_
vbodylen
-
(
size_t
)
FLAGS_http_verbose_max_body_length
<<
" bytes>"
;
-
(
size_t
)
FLAGS_http_verbose_max_body_length
<<
" bytes>"
;
}
}
std
::
cerr
<<
_vmsgbuilder
->
buf
()
<<
std
::
endl
;
std
::
cerr
<<
_vmsgbuilder
->
buf
()
<<
std
::
endl
;
...
@@ -396,7 +398,7 @@ HttpMessage::HttpMessage(bool read_body_progressively)
...
@@ -396,7 +398,7 @@ HttpMessage::HttpMessage(bool read_body_progressively)
,
_body_reader
(
NULL
)
,
_body_reader
(
NULL
)
,
_cur_value
(
NULL
)
,
_cur_value
(
NULL
)
,
_vmsgbuilder
(
NULL
)
,
_vmsgbuilder
(
NULL
)
,
_
body_length
(
0
)
{
,
_
vbodylen
(
0
)
{
http_parser_init
(
&
_parser
,
HTTP_BOTH
);
http_parser_init
(
&
_parser
,
HTTP_BOTH
);
_parser
.
data
=
this
;
_parser
.
data
=
this
;
}
}
...
@@ -534,10 +536,10 @@ std::ostream& operator<<(std::ostream& os, const http_parser& parser) {
...
@@ -534,10 +536,10 @@ std::ostream& operator<<(std::ostream& os, const http_parser& parser) {
// | "CONNECT" ; Section 9.9
// | "CONNECT" ; Section 9.9
// | extension-method
// | extension-method
// extension-method = token
// extension-method = token
void
Serialize
HttpRequest
(
butil
::
IOBuf
*
request
,
void
MakeRaw
HttpRequest
(
butil
::
IOBuf
*
request
,
HttpHeader
*
h
,
HttpHeader
*
h
,
const
butil
::
EndPoint
&
remote_side
,
const
butil
::
EndPoint
&
remote_side
,
const
butil
::
IOBuf
*
content
)
{
const
butil
::
IOBuf
*
content
)
{
butil
::
IOBufBuilder
os
;
butil
::
IOBufBuilder
os
;
os
<<
HttpMethod2Str
(
h
->
method
())
<<
' '
;
os
<<
HttpMethod2Str
(
h
->
method
())
<<
' '
;
const
URI
&
uri
=
h
->
uri
();
const
URI
&
uri
=
h
->
uri
();
...
@@ -611,9 +613,9 @@ void SerializeHttpRequest(butil::IOBuf* request,
...
@@ -611,9 +613,9 @@ void SerializeHttpRequest(butil::IOBuf* request,
// CRLF
// CRLF
// [ message-body ] ; Section 7.2
// [ message-body ] ; Section 7.2
// Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF
// Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF
void
Serialize
HttpResponse
(
butil
::
IOBuf
*
response
,
void
MakeRaw
HttpResponse
(
butil
::
IOBuf
*
response
,
HttpHeader
*
h
,
HttpHeader
*
h
,
butil
::
IOBuf
*
content
)
{
butil
::
IOBuf
*
content
)
{
butil
::
IOBufBuilder
os
;
butil
::
IOBufBuilder
os
;
os
<<
"HTTP/"
<<
h
->
major_version
()
<<
'.'
os
<<
"HTTP/"
<<
h
->
major_version
()
<<
'.'
<<
h
->
minor_version
()
<<
' '
<<
h
->
status_code
()
<<
h
->
minor_version
()
<<
' '
<<
h
->
status_code
()
...
...
src/brpc/details/http_message.h
View file @
4a0927af
...
@@ -113,7 +113,7 @@ private:
...
@@ -113,7 +113,7 @@ private:
protected
:
protected
:
// Only valid when -http_verbose is on
// Only valid when -http_verbose is on
butil
::
IOBufBuilder
*
_vmsgbuilder
;
butil
::
IOBufBuilder
*
_vmsgbuilder
;
size_t
_
body_length
;
size_t
_
vbodylen
;
};
};
std
::
ostream
&
operator
<<
(
std
::
ostream
&
os
,
const
http_parser
&
parser
);
std
::
ostream
&
operator
<<
(
std
::
ostream
&
os
,
const
http_parser
&
parser
);
...
@@ -122,17 +122,17 @@ std::ostream& operator<<(std::ostream& os, const http_parser& parser);
...
@@ -122,17 +122,17 @@ std::ostream& operator<<(std::ostream& os, const http_parser& parser);
// header: may be modified in some cases
// header: may be modified in some cases
// remote_side: used when "Host" is absent
// remote_side: used when "Host" is absent
// content: could be NULL.
// content: could be NULL.
void
Serialize
HttpRequest
(
butil
::
IOBuf
*
request
,
void
MakeRaw
HttpRequest
(
butil
::
IOBuf
*
request
,
HttpHeader
*
header
,
HttpHeader
*
header
,
const
butil
::
EndPoint
&
remote_side
,
const
butil
::
EndPoint
&
remote_side
,
const
butil
::
IOBuf
*
content
);
const
butil
::
IOBuf
*
content
);
// Serialize a http response.
// Serialize a http response.
// header: may be modified in some cases
// header: may be modified in some cases
// content: cleared after usage. could be NULL.
// content: cleared after usage. could be NULL.
void
Serialize
HttpResponse
(
butil
::
IOBuf
*
response
,
void
MakeRaw
HttpResponse
(
butil
::
IOBuf
*
response
,
HttpHeader
*
header
,
HttpHeader
*
header
,
butil
::
IOBuf
*
content
);
butil
::
IOBuf
*
content
);
}
// namespace brpc
}
// namespace brpc
...
...
src/brpc/global.cpp
View file @
4a0927af
...
@@ -504,18 +504,6 @@ static void GlobalInitializeOrDieImpl() {
...
@@ -504,18 +504,6 @@ static void GlobalInitializeOrDieImpl() {
}
}
#endif
#endif
// grpc protocol is based on http2
Protocol
grpc_protocol
=
{
ParseH2Message
,
SerializeHttpRequest
,
PackH2Request
,
ProcessHttpRequest
,
ProcessHttpResponse
,
VerifyHttpRequest
,
ParseHttpServerAddress
,
GetHttpMethodName
,
CONNECTION_TYPE_SINGLE
,
"grpc"
};
if
(
RegisterProtocol
(
PROTOCOL_GRPC
,
grpc_protocol
)
!=
0
)
{
exit
(
1
);
}
// Only valid at client side
// Only valid at client side
Protocol
ubrpc_compack_protocol
=
{
Protocol
ubrpc_compack_protocol
=
{
ParseNsheadMessage
,
ParseNsheadMessage
,
...
...
src/brpc/grpc.cpp
View file @
4a0927af
...
@@ -24,6 +24,30 @@
...
@@ -24,6 +24,30 @@
namespace
brpc
{
namespace
brpc
{
const
char
*
GrpcStatusToString
(
GrpcStatus
s
)
{
switch
(
s
)
{
case
GRPC_OK
:
return
"GRPC_OK"
;
case
GRPC_CANCELED
:
return
"GRPC_CANCELED"
;
case
GRPC_UNKNOWN
:
return
"GRPC_UNKNOWN"
;
case
GRPC_INVALIDARGUMENT
:
return
"GRPC_INVALIDARGUMENT"
;
case
GRPC_DEADLINEEXCEEDED
:
return
"GRPC_DEADLINEEXCEEDED"
;
case
GRPC_NOTFOUND
:
return
"GRPC_NOTFOUND"
;
case
GRPC_ALREADYEXISTS
:
return
"GRPC_ALREADYEXISTS"
;
case
GRPC_PERMISSIONDENIED
:
return
"GRPC_PERMISSIONDENIED"
;
case
GRPC_RESOURCEEXHAUSTED
:
return
"GRPC_RESOURCEEXHAUSTED"
;
case
GRPC_FAILEDPRECONDITION
:
return
"GRPC_FAILEDPRECONDITION"
;
case
GPRC_ABORTED
:
return
"GPRC_ABORTED"
;
case
GRPC_OUTOFRANGE
:
return
"GRPC_OUTOFRANGE"
;
case
GRPC_UNIMPLEMENTED
:
return
"GRPC_UNIMPLEMENTED"
;
case
GRPC_INTERNAL
:
return
"GRPC_INTERNAL"
;
case
GRPC_UNAVAILABLE
:
return
"GRPC_UNAVAILABLE"
;
case
GRPC_DATALOSS
:
return
"GRPC_DATALOSS"
;
case
GRPC_UNAUTHENTICATED
:
return
"GRPC_UNAUTHENTICATED"
;
case
GRPC_MAX
:
return
"GRPC_MAX"
;
}
return
"Unknown-GrpcStatus"
;
}
GrpcStatus
ErrorCodeToGrpcStatus
(
int
error_code
)
{
GrpcStatus
ErrorCodeToGrpcStatus
(
int
error_code
)
{
switch
(
error_code
)
{
switch
(
error_code
)
{
case
0
:
case
0
:
...
...
src/brpc/grpc.h
View file @
4a0927af
...
@@ -142,8 +142,11 @@ enum GrpcStatus {
...
@@ -142,8 +142,11 @@ enum GrpcStatus {
GRPC_MAX
,
GRPC_MAX
,
};
};
GrpcStatus
ErrorCodeToGrpcStatus
(
int
error_code
);
// Get description of the error.
const
char
*
GrpcStatusToString
(
GrpcStatus
);
// Convert between error code and grpc status with similar semantics
GrpcStatus
ErrorCodeToGrpcStatus
(
int
error_code
);
int
GrpcStatusToErrorCode
(
GrpcStatus
grpc_status
);
int
GrpcStatusToErrorCode
(
GrpcStatus
grpc_status
);
void
PercentEncode
(
const
std
::
string
&
str
,
std
::
string
*
str_out
);
void
PercentEncode
(
const
std
::
string
&
str
,
std
::
string
*
str_out
);
...
...
src/brpc/http_header.h
View file @
4a0927af
...
@@ -154,8 +154,6 @@ friend void policy::ProcessHttpRequest(InputMessageBase *msg);
...
@@ -154,8 +154,6 @@ friend void policy::ProcessHttpRequest(InputMessageBase *msg);
std
::
string
_content_type
;
std
::
string
_content_type
;
std
::
string
_unresolved_path
;
std
::
string
_unresolved_path
;
std
::
pair
<
int
,
int
>
_version
;
std
::
pair
<
int
,
int
>
_version
;
int
_h2_stream_id
;
H2Error
_h2_error
;
};
};
const
HttpHeader
&
DefaultHttpHeader
();
const
HttpHeader
&
DefaultHttpHeader
();
...
...
src/brpc/options.proto
View file @
4a0927af
...
@@ -47,7 +47,6 @@ enum ProtocolType {
...
@@ -47,7 +47,6 @@ enum ProtocolType {
PROTOCOL_CDS_AGENT
=
24
;
// Client side only
PROTOCOL_CDS_AGENT
=
24
;
// Client side only
PROTOCOL_ESP
=
25
;
// Client side only
PROTOCOL_ESP
=
25
;
// Client side only
PROTOCOL_HTTP2
=
26
;
PROTOCOL_HTTP2
=
26
;
PROTOCOL_GRPC
=
27
;
}
}
enum
CompressType
{
enum
CompressType
{
...
...
src/brpc/policy/http2_rpc_protocol.cpp
View file @
4a0927af
...
@@ -1592,8 +1592,7 @@ size_t H2UnsentRequest::EstimatedByteSize() {
...
@@ -1592,8 +1592,7 @@ size_t H2UnsentRequest::EstimatedByteSize() {
return
sz
;
return
sz
;
}
}
void
H2UnsentRequest
::
Describe
(
butil
::
IOBuf
*
desc
)
const
{
void
H2UnsentRequest
::
Print
(
std
::
ostream
&
os
)
const
{
butil
::
IOBufBuilder
os
;
os
<<
"[ H2 REQUEST @"
<<
butil
::
my_ip
()
<<
" ]
\n
"
;
os
<<
"[ H2 REQUEST @"
<<
butil
::
my_ip
()
<<
" ]
\n
"
;
for
(
size_t
i
=
0
;
i
<
_size
;
++
i
)
{
for
(
size_t
i
=
0
;
i
<
_size
;
++
i
)
{
os
<<
"> "
<<
_list
[
i
].
name
<<
" = "
<<
_list
[
i
].
value
<<
'\n'
;
os
<<
"> "
<<
_list
[
i
].
name
<<
" = "
<<
_list
[
i
].
value
<<
'\n'
;
...
@@ -1613,33 +1612,23 @@ void H2UnsentRequest::Describe(butil::IOBuf* desc) const {
...
@@ -1613,33 +1612,23 @@ void H2UnsentRequest::Describe(butil::IOBuf* desc) const {
if
(
!
body
->
empty
())
{
if
(
!
body
->
empty
())
{
os
<<
">
\n
"
;
os
<<
">
\n
"
;
}
}
os
.
move_to
(
*
desc
);
os
<<
butil
::
BinaryPrinter
(
*
body
,
FLAGS_http_verbose_max_body_length
);
if
(
body
->
size
()
>
(
size_t
)
FLAGS_http_verbose_max_body_length
)
{
size_t
nskipped
=
body
->
size
()
-
(
size_t
)
FLAGS_http_verbose_max_body_length
;
body
->
append_to
(
desc
,
FLAGS_http_verbose_max_body_length
);
if
(
nskipped
)
{
char
str
[
48
];
snprintf
(
str
,
sizeof
(
str
),
"
\n
<skipped %"
PRIu64
" bytes>"
,
nskipped
);
desc
->
append
(
str
);
}
}
else
{
desc
->
append
(
*
body
);
}
}
}
H2UnsentResponse
::
H2UnsentResponse
(
Controller
*
c
,
int
stream_id
,
bool
grpc
)
H2UnsentResponse
::
H2UnsentResponse
(
Controller
*
c
,
int
stream_id
,
bool
is_
grpc
)
:
_size
(
0
)
:
_size
(
0
)
,
_stream_id
(
stream_id
)
,
_stream_id
(
stream_id
)
,
_http_response
(
c
->
release_http_response
())
,
_http_response
(
c
->
release_http_response
())
,
_
grpc
(
grpc
)
{
,
_
is_grpc
(
is_
grpc
)
{
_data
.
swap
(
c
->
response_attachment
());
_data
.
swap
(
c
->
response_attachment
());
if
(
grpc
)
{
if
(
is_
grpc
)
{
_grpc_status
=
ErrorCodeToGrpcStatus
(
c
->
ErrorCode
());
_grpc_status
=
ErrorCodeToGrpcStatus
(
c
->
ErrorCode
());
PercentEncode
(
c
->
ErrorText
(),
&
_grpc_message
);
PercentEncode
(
c
->
ErrorText
(),
&
_grpc_message
);
}
}
}
}
H2UnsentResponse
*
H2UnsentResponse
::
New
(
Controller
*
c
,
int
stream_id
,
bool
grpc
)
{
H2UnsentResponse
*
H2UnsentResponse
::
New
(
Controller
*
c
,
int
stream_id
,
bool
is_
grpc
)
{
const
HttpHeader
*
const
h
=
&
c
->
http_response
();
const
HttpHeader
*
const
h
=
&
c
->
http_response
();
const
CommonStrings
*
const
common
=
get_common_strings
();
const
CommonStrings
*
const
common
=
get_common_strings
();
const
bool
need_content_length
=
const
bool
need_content_length
=
...
@@ -1650,7 +1639,7 @@ H2UnsentResponse* H2UnsentResponse::New(Controller* c, int stream_id, bool grpc)
...
@@ -1650,7 +1639,7 @@ H2UnsentResponse* H2UnsentResponse::New(Controller* c, int stream_id, bool grpc)
+
(
size_t
)
need_content_type
;
+
(
size_t
)
need_content_type
;
const
size_t
memsize
=
offsetof
(
H2UnsentResponse
,
_list
)
+
const
size_t
memsize
=
offsetof
(
H2UnsentResponse
,
_list
)
+
sizeof
(
HPacker
::
Header
)
*
maxsize
;
sizeof
(
HPacker
::
Header
)
*
maxsize
;
H2UnsentResponse
*
msg
=
new
(
malloc
(
memsize
))
H2UnsentResponse
(
c
,
stream_id
,
grpc
);
H2UnsentResponse
*
msg
=
new
(
malloc
(
memsize
))
H2UnsentResponse
(
c
,
stream_id
,
is_
grpc
);
// :status
// :status
if
(
h
->
status_code
()
==
200
)
{
if
(
h
->
status_code
()
==
200
)
{
msg
->
push
(
common
->
H2_STATUS
,
common
->
STATUS_200
);
msg
->
push
(
common
->
H2_STATUS
,
common
->
STATUS_200
);
...
@@ -1720,18 +1709,17 @@ H2UnsentResponse::AppendAndDestroySelf(butil::IOBuf* out, Socket* socket) {
...
@@ -1720,18 +1709,17 @@ H2UnsentResponse::AppendAndDestroySelf(butil::IOBuf* out, Socket* socket) {
butil
::
IOBuf
frag
;
butil
::
IOBuf
frag
;
appender
.
move_to
(
frag
);
appender
.
move_to
(
frag
);
butil
::
IOBufAppender
trailer_appender
;
butil
::
IOBuf
trailer_frag
;
butil
::
IOBuf
trailer_frag
;
if
(
_grpc
)
{
if
(
_
is_
grpc
)
{
HPacker
::
Header
status_header
(
"grpc-status"
,
HPacker
::
Header
status_header
(
"grpc-status"
,
butil
::
string_printf
(
"%d"
,
_grpc_status
));
butil
::
string_printf
(
"%d"
,
_grpc_status
));
hpacker
.
Encode
(
&
trailer_
appender
,
status_header
,
options
);
hpacker
.
Encode
(
&
appender
,
status_header
,
options
);
if
(
!
_grpc_message
.
empty
())
{
if
(
!
_grpc_message
.
empty
())
{
HPacker
::
Header
msg_header
(
"grpc-message"
,
_grpc_message
);
HPacker
::
Header
msg_header
(
"grpc-message"
,
_grpc_message
);
hpacker
.
Encode
(
&
trailer_
appender
,
msg_header
,
options
);
hpacker
.
Encode
(
&
appender
,
msg_header
,
options
);
}
}
appender
.
move_to
(
trailer_frag
);
}
}
trailer_appender
.
move_to
(
trailer_frag
);
PackH2Message
(
out
,
frag
,
trailer_frag
,
_data
,
_stream_id
,
ctx
);
PackH2Message
(
out
,
frag
,
trailer_frag
,
_data
,
_stream_id
,
ctx
);
return
butil
::
Status
::
OK
();
return
butil
::
Status
::
OK
();
...
@@ -1752,8 +1740,7 @@ size_t H2UnsentResponse::EstimatedByteSize() {
...
@@ -1752,8 +1740,7 @@ size_t H2UnsentResponse::EstimatedByteSize() {
return
sz
;
return
sz
;
}
}
void
H2UnsentResponse
::
Describe
(
butil
::
IOBuf
*
desc
)
const
{
void
H2UnsentResponse
::
Print
(
std
::
ostream
&
os
)
const
{
butil
::
IOBufBuilder
os
;
os
<<
"[ H2 RESPONSE @"
<<
butil
::
my_ip
()
<<
" ]
\n
"
;
os
<<
"[ H2 RESPONSE @"
<<
butil
::
my_ip
()
<<
" ]
\n
"
;
for
(
size_t
i
=
0
;
i
<
_size
;
++
i
)
{
for
(
size_t
i
=
0
;
i
<
_size
;
++
i
)
{
os
<<
"> "
<<
_list
[
i
].
name
<<
" = "
<<
_list
[
i
].
value
<<
'\n'
;
os
<<
"> "
<<
_list
[
i
].
name
<<
" = "
<<
_list
[
i
].
value
<<
'\n'
;
...
@@ -1767,18 +1754,7 @@ void H2UnsentResponse::Describe(butil::IOBuf* desc) const {
...
@@ -1767,18 +1754,7 @@ void H2UnsentResponse::Describe(butil::IOBuf* desc) const {
if
(
!
_data
.
empty
())
{
if
(
!
_data
.
empty
())
{
os
<<
">
\n
"
;
os
<<
">
\n
"
;
}
}
os
.
move_to
(
*
desc
);
os
<<
butil
::
BinaryPrinter
(
_data
,
FLAGS_http_verbose_max_body_length
);
if
(
_data
.
size
()
>
(
size_t
)
FLAGS_http_verbose_max_body_length
)
{
size_t
nskipped
=
_data
.
size
()
-
(
size_t
)
FLAGS_http_verbose_max_body_length
;
_data
.
append_to
(
desc
,
FLAGS_http_verbose_max_body_length
);
if
(
nskipped
)
{
char
str
[
48
];
snprintf
(
str
,
sizeof
(
str
),
"
\n
<skipped %"
PRIu64
" bytes>"
,
nskipped
);
desc
->
append
(
str
);
}
}
else
{
desc
->
append
(
_data
);
}
}
}
void
PackH2Request
(
butil
::
IOBuf
*
,
void
PackH2Request
(
butil
::
IOBuf
*
,
...
@@ -1806,9 +1782,7 @@ void PackH2Request(butil::IOBuf*,
...
@@ -1806,9 +1782,7 @@ void PackH2Request(butil::IOBuf*,
*
user_message
=
h2_req
;
*
user_message
=
h2_req
;
if
(
FLAGS_http_verbose
)
{
if
(
FLAGS_http_verbose
)
{
butil
::
IOBuf
desc
;
std
::
cerr
<<
*
h2_req
<<
std
::
endl
;
h2_req
->
Describe
(
&
desc
);
std
::
cerr
<<
desc
<<
std
::
endl
;
}
}
}
}
...
...
src/brpc/policy/http2_rpc_protocol.h
View file @
4a0927af
...
@@ -135,7 +135,7 @@ friend void PackH2Request(butil::IOBuf*, SocketMessage**,
...
@@ -135,7 +135,7 @@ friend void PackH2Request(butil::IOBuf*, SocketMessage**,
Controller
*
,
const
butil
::
IOBuf
&
,
const
Authenticator
*
);
Controller
*
,
const
butil
::
IOBuf
&
,
const
Authenticator
*
);
public
:
public
:
static
H2UnsentRequest
*
New
(
Controller
*
c
);
static
H2UnsentRequest
*
New
(
Controller
*
c
);
void
Describe
(
butil
::
IOBuf
*
)
const
;
void
Print
(
std
::
ostream
&
)
const
;
int
AddRefManually
()
int
AddRefManually
()
{
return
_nref
.
fetch_add
(
1
,
butil
::
memory_order_relaxed
);
}
{
return
_nref
.
fetch_add
(
1
,
butil
::
memory_order_relaxed
);
}
...
@@ -194,9 +194,9 @@ private:
...
@@ -194,9 +194,9 @@ private:
class
H2UnsentResponse
:
public
SocketMessage
{
class
H2UnsentResponse
:
public
SocketMessage
{
public
:
public
:
static
H2UnsentResponse
*
New
(
Controller
*
c
,
int
stream_id
,
bool
grpc
);
static
H2UnsentResponse
*
New
(
Controller
*
c
,
int
stream_id
,
bool
is_
grpc
);
void
Destroy
();
void
Destroy
();
void
Describe
(
butil
::
IOBuf
*
)
const
;
void
Print
(
std
::
ostream
&
)
const
;
// @SocketMessage
// @SocketMessage
butil
::
Status
AppendAndDestroySelf
(
butil
::
IOBuf
*
out
,
Socket
*
)
override
;
butil
::
Status
AppendAndDestroySelf
(
butil
::
IOBuf
*
out
,
Socket
*
)
override
;
size_t
EstimatedByteSize
()
override
;
size_t
EstimatedByteSize
()
override
;
...
@@ -208,7 +208,7 @@ private:
...
@@ -208,7 +208,7 @@ private:
void
push
(
const
std
::
string
&
name
,
const
std
::
string
&
value
)
void
push
(
const
std
::
string
&
name
,
const
std
::
string
&
value
)
{
new
(
&
_list
[
_size
++
])
HPacker
::
Header
(
name
,
value
);
}
{
new
(
&
_list
[
_size
++
])
HPacker
::
Header
(
name
,
value
);
}
H2UnsentResponse
(
Controller
*
c
,
int
stream_id
,
bool
grpc
);
H2UnsentResponse
(
Controller
*
c
,
int
stream_id
,
bool
is_
grpc
);
~
H2UnsentResponse
()
{}
~
H2UnsentResponse
()
{}
H2UnsentResponse
(
const
H2UnsentResponse
&
);
H2UnsentResponse
(
const
H2UnsentResponse
&
);
void
operator
=
(
const
H2UnsentResponse
&
);
void
operator
=
(
const
H2UnsentResponse
&
);
...
@@ -218,7 +218,7 @@ private:
...
@@ -218,7 +218,7 @@ private:
uint32_t
_stream_id
;
uint32_t
_stream_id
;
std
::
unique_ptr
<
HttpHeader
>
_http_response
;
std
::
unique_ptr
<
HttpHeader
>
_http_response
;
butil
::
IOBuf
_data
;
butil
::
IOBuf
_data
;
bool
_grpc
;
bool
_
is_
grpc
;
GrpcStatus
_grpc_status
;
GrpcStatus
_grpc_status
;
std
::
string
_grpc_message
;
std
::
string
_grpc_message
;
HPacker
::
Header
_list
[
0
];
HPacker
::
Header
_list
[
0
];
...
@@ -409,6 +409,15 @@ inline bool H2Context::RunOutStreams() const {
...
@@ -409,6 +409,15 @@ inline bool H2Context::RunOutStreams() const {
return
(
_last_client_stream_id
>
0x7FFFFFFF
);
return
(
_last_client_stream_id
>
0x7FFFFFFF
);
}
}
inline
std
::
ostream
&
operator
<<
(
std
::
ostream
&
os
,
const
H2UnsentRequest
&
req
)
{
req
.
Print
(
os
);
return
os
;
}
inline
std
::
ostream
&
operator
<<
(
std
::
ostream
&
os
,
const
H2UnsentResponse
&
res
)
{
res
.
Print
(
os
);
return
os
;
}
}
// namespace policy
}
// namespace policy
}
// namespace brpc
}
// namespace brpc
...
...
src/brpc/policy/http_rpc_protocol.cpp
View file @
4a0927af
...
@@ -24,6 +24,7 @@
...
@@ -24,6 +24,7 @@
#include "butil/string_splitter.h" // StringMultiSplitter
#include "butil/string_splitter.h" // StringMultiSplitter
#include "butil/string_printf.h"
#include "butil/string_printf.h"
#include "butil/time.h"
#include "butil/time.h"
#include "butil/sys_byteorder.h"
#include "brpc/compress.h"
#include "brpc/compress.h"
#include "brpc/errno.pb.h" // ENOSERVICE, ENOMETHOD
#include "brpc/errno.pb.h" // ENOSERVICE, ENOMETHOD
#include "brpc/controller.h" // Controller
#include "brpc/controller.h" // Controller
...
@@ -111,7 +112,6 @@ CommonStrings::CommonStrings()
...
@@ -111,7 +112,6 @@ CommonStrings::CommonStrings()
,
ACCEPT_ENCODING
(
"accept-encoding"
)
,
ACCEPT_ENCODING
(
"accept-encoding"
)
,
CONTENT_ENCODING
(
"content-encoding"
)
,
CONTENT_ENCODING
(
"content-encoding"
)
,
CONTENT_LENGTH
(
"content-length"
)
,
CONTENT_LENGTH
(
"content-length"
)
,
IDENTITY
(
"identity"
)
,
GZIP
(
"gzip"
)
,
GZIP
(
"gzip"
)
,
CONNECTION
(
"connection"
)
,
CONNECTION
(
"connection"
)
,
KEEP_ALIVE
(
"keep-alive"
)
,
KEEP_ALIVE
(
"keep-alive"
)
...
@@ -129,11 +129,11 @@ CommonStrings::CommonStrings()
...
@@ -129,11 +129,11 @@ CommonStrings::CommonStrings()
,
H2_METHOD
(
":method"
)
,
H2_METHOD
(
":method"
)
,
METHOD_GET
(
"GET"
)
,
METHOD_GET
(
"GET"
)
,
METHOD_POST
(
"POST"
)
,
METHOD_POST
(
"POST"
)
,
CONTENT_TYPE_GRPC
(
"application/grpc"
)
,
TE
(
"te"
)
,
TE
(
"te"
)
,
TRAILERS
(
"trailers"
)
,
TRAILERS
(
"trailers"
)
,
GRPC_ENCODING
(
"grpc-encoding"
)
,
GRPC_ENCODING
(
"grpc-encoding"
)
,
GRPC_ACCEPT_ENCODING
(
"grpc-accept-encoding"
)
,
GRPC_ACCEPT_ENCODING
(
"grpc-accept-encoding"
)
,
GRPC_ACCEPT_ENCODING_VALUE
(
"identity,gzip"
)
,
GRPC_STATUS
(
"grpc-status"
)
,
GRPC_STATUS
(
"grpc-status"
)
,
GRPC_MESSAGE
(
"grpc-message"
)
,
GRPC_MESSAGE
(
"grpc-message"
)
{}
{}
...
@@ -150,35 +150,46 @@ int InitCommonStrings() {
...
@@ -150,35 +150,46 @@ int InitCommonStrings() {
static
const
int
ALLOW_UNUSED
force_creation_of_common
=
InitCommonStrings
();
static
const
int
ALLOW_UNUSED
force_creation_of_common
=
InitCommonStrings
();
const
CommonStrings
*
get_common_strings
()
{
return
common
;
}
const
CommonStrings
*
get_common_strings
()
{
return
common
;
}
HttpContentType
ParseContentType
(
butil
::
StringPiece
content_type
)
{
HttpContentType
ParseContentType
(
butil
::
StringPiece
ct
,
bool
*
is_grpc_ct
)
{
const
butil
::
StringPiece
prefix
=
"application/"
;
const
butil
::
StringPiece
json
=
"json"
;
const
butil
::
StringPiece
proto
=
"proto"
;
const
butil
::
StringPiece
grpc
=
"grpc"
;
// According to http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.7
// According to http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.7
// media-type = type "/" subtype *( ";" parameter )
// media-type = type "/" subtype *( ";" parameter )
// type = token
// type = token
// subtype = token
// subtype = token
if
(
!
content_type
.
starts_with
(
prefix
))
{
const
butil
::
StringPiece
prefix
=
"application/"
;
if
(
!
ct
.
starts_with
(
prefix
))
{
return
HTTP_CONTENT_OTHERS
;
return
HTTP_CONTENT_OTHERS
;
}
}
content_type
.
remove_prefix
(
prefix
.
size
());
ct
.
remove_prefix
(
prefix
.
size
());
if
(
ct
.
starts_with
(
"grpc"
))
{
if
(
ct
.
size
()
==
(
size_t
)
4
||
ct
[
4
]
==
';'
)
{
if
(
is_grpc_ct
)
{
*
is_grpc_ct
=
true
;
}
// assume that the default content type for grpc is proto.
return
HTTP_CONTENT_PROTO
;
}
else
if
(
ct
[
4
]
==
'+'
)
{
ct
.
remove_prefix
(
5
);
if
(
is_grpc_ct
)
{
*
is_grpc_ct
=
true
;
}
}
// else don't change ct. Note that "grpcfoo" is a valid but non-grpc
// content-type in the sense of format.
}
HttpContentType
type
=
HTTP_CONTENT_OTHERS
;
HttpContentType
type
=
HTTP_CONTENT_OTHERS
;
if
(
c
ontent_type
.
starts_with
(
json
))
{
if
(
c
t
.
starts_with
(
"json"
))
{
type
=
HTTP_CONTENT_JSON
;
type
=
HTTP_CONTENT_JSON
;
c
ontent_type
.
remove_prefix
(
json
.
size
()
);
c
t
.
remove_prefix
(
4
);
}
else
if
(
c
ontent_type
.
starts_with
(
proto
))
{
}
else
if
(
c
t
.
starts_with
(
"proto"
))
{
type
=
HTTP_CONTENT_PROTO
;
type
=
HTTP_CONTENT_PROTO
;
content_type
.
remove_prefix
(
proto
.
size
());
ct
.
remove_prefix
(
5
);
}
else
if
(
content_type
.
starts_with
(
grpc
))
{
type
=
HTTP_CONTENT_GRPC
;
content_type
.
remove_prefix
(
grpc
.
size
());
}
else
{
}
else
{
return
HTTP_CONTENT_OTHERS
;
return
HTTP_CONTENT_OTHERS
;
}
}
return
content_type
.
empty
()
||
content_type
.
front
()
==
';'
return
(
ct
.
empty
()
||
ct
.
front
()
==
';'
)
?
type
:
HTTP_CONTENT_OTHERS
;
?
type
:
HTTP_CONTENT_OTHERS
;
}
}
static
void
PrintMessage
(
const
butil
::
IOBuf
&
inbuf
,
static
void
PrintMessage
(
const
butil
::
IOBuf
&
inbuf
,
...
@@ -201,32 +212,39 @@ static void PrintMessage(const butil::IOBuf& inbuf,
...
@@ -201,32 +212,39 @@ static void PrintMessage(const butil::IOBuf& inbuf,
if
(
buf2
.
size
()
==
last_size
)
{
if
(
buf2
.
size
()
==
last_size
)
{
buf2
.
pop_back
(
2
);
// remove "> "
buf2
.
pop_back
(
2
);
// remove "> "
}
}
buf2
.
append
(
buf1
);
if
(
!
has_content
)
{
if
(
!
has_content
)
{
buf2
.
append
(
buf1
)
;
std
::
cerr
<<
buf2
<<
std
::
endl
;
}
else
{
}
else
{
uint64_t
nskipped
=
0
;
std
::
cerr
<<
butil
::
PrintedAsBinary
(
if
(
buf1
.
size
()
>
(
size_t
)
FLAGS_http_verbose_max_body_length
)
{
buf2
,
buf2
.
size
()
+
FLAGS_http_verbose_max_body_length
)
<<
std
::
endl
;
nskipped
=
buf1
.
size
()
-
(
size_t
)
FLAGS_http_verbose_max_body_length
;
buf1
.
pop_back
(
nskipped
);
}
buf2
.
append
(
buf1
);
if
(
nskipped
)
{
snprintf
(
str
,
sizeof
(
str
),
"
\n
<skipped %"
PRIu64
" bytes>"
,
nskipped
);
buf2
.
append
(
str
);
}
}
}
std
::
cerr
<<
buf2
<<
std
::
endl
;
}
}
inline
uint32_t
ReadBigEndian4Bytes
(
const
void
*
void_buf
)
{
static
void
AddGrpcPrefix
(
butil
::
IOBuf
*
body
,
bool
compressed
)
{
uint32_t
ret
=
0
;
char
buf
[
5
];
char
*
p
=
(
char
*
)
&
ret
;
buf
[
0
]
=
(
compressed
?
1
:
0
);
const
char
*
buf
=
(
const
char
*
)
void_buf
;
*
(
uint32_t
*
)(
buf
+
1
)
=
butil
::
HostToNet32
(
body
->
size
());
p
[
3
]
=
buf
[
0
];
butil
::
IOBuf
tmp_buf
;
p
[
2
]
=
buf
[
1
];
tmp_buf
.
append
(
buf
,
sizeof
(
buf
));
p
[
1
]
=
buf
[
2
];
tmp_buf
.
append
(
butil
::
IOBuf
::
Movable
(
*
body
));
p
[
0
]
=
buf
[
3
];
body
->
swap
(
tmp_buf
);
return
ret
;
}
static
bool
RemoveGrpcPrefix
(
butil
::
IOBuf
*
body
,
bool
*
compressed
)
{
if
(
body
->
empty
())
{
*
compressed
=
false
;
return
true
;
}
const
size_t
sz
=
body
->
size
();
if
(
sz
<
(
size_t
)
5
)
{
return
false
;
}
char
buf
[
5
];
body
->
cutn
(
buf
,
sizeof
(
buf
));
*
compressed
=
buf
[
0
];
const
size_t
message_length
=
butil
::
NetToHost32
(
*
(
uint32_t
*
)(
buf
+
1
));
return
(
message_length
+
5
==
sz
);
}
}
void
ProcessHttpResponse
(
InputMessageBase
*
msg
)
{
void
ProcessHttpResponse
(
InputMessageBase
*
msg
)
{
...
@@ -271,19 +289,12 @@ void ProcessHttpResponse(InputMessageBase* msg) {
...
@@ -271,19 +289,12 @@ void ProcessHttpResponse(InputMessageBase* msg) {
CHECK
(
cntl
->
response_attachment
().
empty
());
CHECK
(
cntl
->
response_attachment
().
empty
());
const
int
saved_error
=
cntl
->
ErrorCode
();
const
int
saved_error
=
cntl
->
ErrorCode
();
char
grpc_compressed
=
false
;
bool
is_grpc_ct
=
false
;
bool
grpc_protocol
=
const
HttpContentType
content_type
=
ParseContentType
(
res_header
->
content_type
())
==
HTTP_CONTENT_GRPC
;
ParseContentType
(
res_header
->
content_type
(),
&
is_grpc_ct
);
if
(
grpc_protocol
&&
!
res_body
.
empty
())
{
const
bool
is_grpc
=
(
is_http2
&&
is_grpc_ct
);
/* 4 is the size of grpc Message-Length in Length-Prefixed-Message*/
bool
grpc_compressed
=
false
;
// only valid when is_grpc is true.
char
buf
[
4
];
res_body
.
cut1
(
&
grpc_compressed
);
res_body
.
cutn
(
buf
,
4
);
int
message_length
=
ReadBigEndian4Bytes
(
buf
);
CHECK
((
size_t
)
message_length
==
res_body
.
length
())
<<
message_length
<<
" vs "
<<
res_body
.
length
();
}
do
{
do
{
if
(
!
is_http2
)
{
if
(
!
is_http2
)
{
// If header has "Connection: close", close the connection.
// If header has "Connection: close", close the connection.
...
@@ -297,9 +308,32 @@ void ProcessHttpResponse(InputMessageBase* msg) {
...
@@ -297,9 +308,32 @@ void ProcessHttpResponse(InputMessageBase* msg) {
socket
->
SetFailed
();
socket
->
SetFailed
();
}
}
}
}
}
else
if
(
is_grpc
)
{
if
(
!
RemoveGrpcPrefix
(
&
res_body
,
&
grpc_compressed
))
{
cntl
->
SetFailed
(
ERESPONSE
,
"Invalid gRPC response"
);
break
;
}
const
std
::
string
*
grpc_status
=
res_header
->
GetHeader
(
common
->
GRPC_STATUS
);
if
(
grpc_status
)
{
// TODO: More strict parsing
GrpcStatus
status
=
(
GrpcStatus
)
strtol
(
grpc_status
->
data
(),
NULL
,
10
);
if
(
status
!=
GRPC_OK
)
{
const
std
::
string
*
grpc_message
=
res_header
->
GetHeader
(
common
->
GRPC_MESSAGE
);
if
(
grpc_message
)
{
std
::
string
message_decoded
;
PercentDecode
(
*
grpc_message
,
&
message_decoded
);
cntl
->
SetFailed
(
GrpcStatusToErrorCode
(
status
),
"%s"
,
message_decoded
.
c_str
());
}
else
{
cntl
->
SetFailed
(
GrpcStatusToErrorCode
(
status
),
"%s"
,
GrpcStatusToString
(
status
));
}
break
;
}
}
}
}
if
(
imsg_guard
->
read_body_progressively
())
{
if
(
imsg_guard
->
read_body_progressively
())
{
// Set RPA if needed
// Set RPA if needed
accessor
.
set_readable_progressive_attachment
(
imsg_guard
.
get
());
accessor
.
set_readable_progressive_attachment
(
imsg_guard
.
get
());
...
@@ -356,52 +390,27 @@ void ProcessHttpResponse(InputMessageBase* msg) {
...
@@ -356,52 +390,27 @@ void ProcessHttpResponse(InputMessageBase* msg) {
}
}
break
;
break
;
}
}
if
(
grpc_protocol
)
{
const
std
::
string
*
grpc_status
=
res_header
->
GetHeader
(
common
->
GRPC_STATUS
);
const
std
::
string
*
grpc_message
=
res_header
->
GetHeader
(
common
->
GRPC_MESSAGE
);
if
(
grpc_status
)
{
GrpcStatus
status
=
(
GrpcStatus
)
strtol
(
grpc_status
->
data
(),
NULL
,
10
);
if
(
status
!=
GRPC_OK
)
{
std
::
string
message_decoded
;
if
(
grpc_message
)
{
PercentDecode
(
*
grpc_message
,
&
message_decoded
);
}
else
{
message_decoded
=
"Unknown grpc error"
;
}
cntl
->
SetFailed
(
GrpcStatusToErrorCode
(
status
),
"%s"
,
message_decoded
.
c_str
());
break
;
}
}
}
if
(
cntl
->
response
()
==
NULL
||
if
(
cntl
->
response
()
==
NULL
||
cntl
->
response
()
->
GetDescriptor
()
->
field_count
()
==
0
)
{
cntl
->
response
()
->
GetDescriptor
()
->
field_count
()
==
0
)
{
// a http call, content is the "real response".
// a http call, content is the "real response".
cntl
->
response_attachment
().
swap
(
res_body
);
cntl
->
response_attachment
().
swap
(
res_body
);
break
;
break
;
}
}
const
HttpContentType
content_type
=
ParseContentType
(
res_header
->
content_type
());
const
std
::
string
*
encoding
=
NULL
;
if
(
content_type
!=
HTTP_CONTENT_PROTO
&&
if
(
is_grpc
)
{
content_type
!=
HTTP_CONTENT_JSON
&&
if
(
grpc_compressed
)
{
content_type
!=
HTTP_CONTENT_GRPC
)
{
encoding
=
res_header
->
GetHeader
(
common
->
GRPC_ENCODING
);
cntl
->
SetFailed
(
ERESPONSE
,
"content-type=%s is neither %s nor %s or %s"
if
(
encoding
==
NULL
)
{
"when response is not NULL"
,
cntl
->
SetFailed
(
ERESPONSE
,
"Fail to find header `grpc-encoding'"
res_header
->
content_type
().
c_str
(),
" in compressed gRPC response"
);
common
->
CONTENT_TYPE_JSON
.
c_str
(),
break
;
common
->
CONTENT_TYPE_PROTO
.
c_str
(),
}
common
->
CONTENT_TYPE_GRPC
.
c_str
());
}
break
;
}
else
{
encoding
=
res_header
->
GetHeader
(
common
->
CONTENT_ENCODING
);
}
}
const
std
::
string
*
encoding
=
if
(
encoding
!=
NULL
&&
*
encoding
==
common
->
GZIP
)
{
res_header
->
GetHeader
(
common
->
CONTENT_ENCODING
);
const
std
::
string
*
grpc_encoding
=
res_header
->
GetHeader
(
common
->
GRPC_ENCODING
);
if
((
encoding
!=
NULL
&&
*
encoding
==
common
->
GZIP
)
||
(
grpc_compressed
&&
grpc_encoding
!=
NULL
&&
*
grpc_encoding
==
common
->
GZIP
))
{
TRACEPRINTF
(
"Decompressing response=%lu"
,
TRACEPRINTF
(
"Decompressing response=%lu"
,
(
unsigned
long
)
res_body
.
size
());
(
unsigned
long
)
res_body
.
size
());
butil
::
IOBuf
uncompressed
;
butil
::
IOBuf
uncompressed
;
...
@@ -411,13 +420,12 @@ void ProcessHttpResponse(InputMessageBase* msg) {
...
@@ -411,13 +420,12 @@ void ProcessHttpResponse(InputMessageBase* msg) {
}
}
res_body
.
swap
(
uncompressed
);
res_body
.
swap
(
uncompressed
);
}
}
if
(
content_type
==
HTTP_CONTENT_PROTO
||
if
(
content_type
==
HTTP_CONTENT_PROTO
)
{
content_type
==
HTTP_CONTENT_GRPC
)
{
if
(
!
ParsePbFromIOBuf
(
cntl
->
response
(),
res_body
))
{
if
(
!
ParsePbFromIOBuf
(
cntl
->
response
(),
res_body
))
{
cntl
->
SetFailed
(
ERESPONSE
,
"Fail to parse content"
);
cntl
->
SetFailed
(
ERESPONSE
,
"Fail to parse content"
);
break
;
break
;
}
}
}
else
{
}
else
if
(
content_type
==
HTTP_CONTENT_JSON
)
{
// message body is json
// message body is json
butil
::
IOBufAsZeroCopyInputStream
wrapper
(
res_body
);
butil
::
IOBufAsZeroCopyInputStream
wrapper
(
res_body
);
std
::
string
err
;
std
::
string
err
;
...
@@ -427,6 +435,11 @@ void ProcessHttpResponse(InputMessageBase* msg) {
...
@@ -427,6 +435,11 @@ void ProcessHttpResponse(InputMessageBase* msg) {
cntl
->
SetFailed
(
ERESPONSE
,
"Fail to parse content, %s"
,
err
.
c_str
());
cntl
->
SetFailed
(
ERESPONSE
,
"Fail to parse content, %s"
,
err
.
c_str
());
break
;
break
;
}
}
}
else
{
cntl
->
SetFailed
(
ERESPONSE
,
"Unknown content-type=%s when response is not NULL"
,
res_header
->
content_type
().
c_str
());
break
;
}
}
}
while
(
0
);
}
while
(
0
);
...
@@ -436,17 +449,11 @@ void ProcessHttpResponse(InputMessageBase* msg) {
...
@@ -436,17 +449,11 @@ void ProcessHttpResponse(InputMessageBase* msg) {
accessor
.
OnResponse
(
cid
,
saved_error
);
accessor
.
OnResponse
(
cid
,
saved_error
);
}
}
inline
void
WriteBigEndian4Bytes
(
char
*
buf
,
uint32_t
val
)
{
const
char
*
p
=
(
const
char
*
)
&
val
;
buf
[
0
]
=
p
[
3
];
buf
[
1
]
=
p
[
2
];
buf
[
2
]
=
p
[
1
];
buf
[
3
]
=
p
[
0
];
}
void
SerializeHttpRequest
(
butil
::
IOBuf
*
/*not used*/
,
void
SerializeHttpRequest
(
butil
::
IOBuf
*
/*not used*/
,
Controller
*
cntl
,
Controller
*
cntl
,
const
google
::
protobuf
::
Message
*
request
)
{
const
google
::
protobuf
::
Message
*
request
)
{
const
bool
is_http2
=
(
cntl
->
request_protocol
()
==
PROTOCOL_HTTP2
);
bool
is_grpc
=
false
;
if
(
request
!=
NULL
)
{
if
(
request
!=
NULL
)
{
// If request is not NULL, message body will be serialized json,
// If request is not NULL, message body will be serialized json,
if
(
!
request
->
IsInitialized
())
{
if
(
!
request
->
IsInitialized
())
{
...
@@ -459,18 +466,18 @@ void SerializeHttpRequest(butil::IOBuf* /*not used*/,
...
@@ -459,18 +466,18 @@ void SerializeHttpRequest(butil::IOBuf* /*not used*/,
"when request is not NULL"
);
"when request is not NULL"
);
}
}
butil
::
IOBufAsZeroCopyOutputStream
wrapper
(
&
cntl
->
request_attachment
());
butil
::
IOBufAsZeroCopyOutputStream
wrapper
(
&
cntl
->
request_attachment
());
bool
is_grpc_ct
=
false
;
const
HttpContentType
content_type
const
HttpContentType
content_type
=
ParseContentType
(
cntl
->
http_request
().
content_type
()
);
=
ParseContentType
(
cntl
->
http_request
().
content_type
(),
&
is_grpc_ct
);
i
f
(
content_type
==
HTTP_CONTENT_PROTO
||
i
s_grpc
=
(
is_http2
&&
is_grpc_ct
);
cntl
->
request_protocol
()
==
PROTOCOL_GRPC
)
{
if
(
content_type
==
HTTP_CONTENT_PROTO
)
{
// Serialize content as protobuf
// Serialize content as protobuf
if
(
!
request
->
SerializeToZeroCopyStream
(
&
wrapper
))
{
if
(
!
request
->
SerializeToZeroCopyStream
(
&
wrapper
))
{
cntl
->
request_attachment
().
clear
();
cntl
->
request_attachment
().
clear
();
return
cntl
->
SetFailed
(
EREQUEST
,
"Fail to serialize %s"
,
return
cntl
->
SetFailed
(
EREQUEST
,
"Fail to serialize %s"
,
request
->
GetTypeName
().
c_str
());
request
->
GetTypeName
().
c_str
());
}
}
}
else
{
}
else
{
// Serialize content as json
// Serialize content as json
std
::
string
err
;
std
::
string
err
;
json2pb
::
Pb2JsonOptions
opt
;
json2pb
::
Pb2JsonOptions
opt
;
opt
.
bytes_to_base64
=
cntl
->
has_pb_bytes_to_base64
();
opt
.
bytes_to_base64
=
cntl
->
has_pb_bytes_to_base64
();
...
@@ -509,7 +516,7 @@ void SerializeHttpRequest(butil::IOBuf* /*not used*/,
...
@@ -509,7 +516,7 @@ void SerializeHttpRequest(butil::IOBuf* /*not used*/,
butil
::
IOBuf
compressed
;
butil
::
IOBuf
compressed
;
if
(
GzipCompress
(
cntl
->
request_attachment
(),
&
compressed
,
NULL
))
{
if
(
GzipCompress
(
cntl
->
request_attachment
(),
&
compressed
,
NULL
))
{
cntl
->
request_attachment
().
swap
(
compressed
);
cntl
->
request_attachment
().
swap
(
compressed
);
if
(
cntl
->
request_protocol
()
==
PROTOCOL_GRPC
)
{
if
(
is_grpc
)
{
grpc_compressed
=
true
;
grpc_compressed
=
true
;
cntl
->
http_request
().
SetHeader
(
common
->
GRPC_ENCODING
,
common
->
GZIP
);
cntl
->
http_request
().
SetHeader
(
common
->
GRPC_ENCODING
,
common
->
GZIP
);
}
else
{
}
else
{
...
@@ -529,37 +536,26 @@ void SerializeHttpRequest(butil::IOBuf* /*not used*/,
...
@@ -529,37 +536,26 @@ void SerializeHttpRequest(butil::IOBuf* /*not used*/,
"%llu"
,
(
unsigned
long
long
)
cntl
->
log_id
()));
"%llu"
,
(
unsigned
long
long
)
cntl
->
log_id
()));
}
}
// HTTP before 1.1 needs to set keep-alive explicitly.
if
(
!
is_http2
)
{
if
(
header
->
before_http_1_1
()
&&
// HTTP before 1.1 needs to set keep-alive explicitly.
cntl
->
connection_type
()
!=
CONNECTION_TYPE_SHORT
&&
if
(
header
->
before_http_1_1
()
&&
header
->
GetHeader
(
common
->
CONNECTION
)
==
NULL
)
{
cntl
->
connection_type
()
!=
CONNECTION_TYPE_SHORT
&&
header
->
SetHeader
(
common
->
CONNECTION
,
common
->
KEEP_ALIVE
);
header
->
GetHeader
(
common
->
CONNECTION
)
==
NULL
)
{
}
header
->
SetHeader
(
common
->
CONNECTION
,
common
->
KEEP_ALIVE
);
}
if
(
cntl
->
request_protocol
()
==
PROTOCOL_HTTP2
||
}
else
{
cntl
->
request_protocol
()
==
PROTOCOL_GRPC
)
{
cntl
->
set_stream_creator
(
get_h2_global_stream_creator
());
cntl
->
set_stream_creator
(
get_h2_global_stream_creator
());
}
if
(
is_grpc
)
{
/*
if
(
cntl
->
request_protocol
()
==
PROTOCOL_GRPC
)
{
header->SetHeader(common->GRPC_ACCEPT_ENCODING,
// always tell client gzip support
common->GRPC_ACCEPT_ENCODING_VALUE);
// TODO(zhujiashun): add zlib and snappy?
*/
header
->
SetHeader
(
common
->
GRPC_ACCEPT_ENCODING
,
// TODO: do we need this?
common
->
IDENTITY
+
","
+
common
->
GZIP
);
header
->
SetHeader
(
common
->
TE
,
common
->
TRAILERS
);
header
->
set_content_type
(
common
->
CONTENT_TYPE_GRPC
);
header
->
SetHeader
(
common
->
TE
,
common
->
TRAILERS
);
// Append compressed and length before body
butil
::
IOBuf
tmp_buf
;
AddGrpcPrefix
(
&
cntl
->
request_attachment
(),
grpc_compressed
);
// Compressed-Flag as 0 / 1, encoded as 1 byte unsigned integer
if
(
grpc_compressed
)
{
tmp_buf
.
append
(
"
\1
"
,
1
);
}
else
{
tmp_buf
.
append
(
"
\0
"
,
1
);
}
}
char
size_buf
[
4
];
WriteBigEndian4Bytes
(
size_buf
,
cntl
->
request_attachment
().
size
());
tmp_buf
.
append
(
size_buf
,
4
);
tmp_buf
.
append
(
cntl
->
request_attachment
());
cntl
->
request_attachment
().
swap
(
tmp_buf
);
}
}
// Set url to /ServiceName/MethodName when we're about to call protobuf
// Set url to /ServiceName/MethodName when we're about to call protobuf
...
@@ -612,8 +608,8 @@ void PackHttpRequest(butil::IOBuf* buf,
...
@@ -612,8 +608,8 @@ void PackHttpRequest(butil::IOBuf* buf,
// may not echo back this field. But we send it anyway.
// may not echo back this field. But we send it anyway.
accessor
.
get_sending_socket
()
->
set_correlation_id
(
correlation_id
);
accessor
.
get_sending_socket
()
->
set_correlation_id
(
correlation_id
);
Serialize
HttpRequest
(
buf
,
header
,
cntl
->
remote_side
(),
MakeRaw
HttpRequest
(
buf
,
header
,
cntl
->
remote_side
(),
&
cntl
->
request_attachment
());
&
cntl
->
request_attachment
());
if
(
FLAGS_http_verbose
)
{
if
(
FLAGS_http_verbose
)
{
PrintMessage
(
*
buf
,
true
,
true
);
PrintMessage
(
*
buf
,
true
,
true
);
}
}
...
@@ -622,10 +618,7 @@ void PackHttpRequest(butil::IOBuf* buf,
...
@@ -622,10 +618,7 @@ void PackHttpRequest(butil::IOBuf* buf,
inline
bool
SupportGzip
(
Controller
*
cntl
)
{
inline
bool
SupportGzip
(
Controller
*
cntl
)
{
const
std
::
string
*
encodings
=
const
std
::
string
*
encodings
=
cntl
->
http_request
().
GetHeader
(
common
->
ACCEPT_ENCODING
);
cntl
->
http_request
().
GetHeader
(
common
->
ACCEPT_ENCODING
);
const
std
::
string
*
grpc_encodings
=
return
(
encodings
&&
encodings
->
find
(
common
->
GZIP
)
!=
std
::
string
::
npos
);
cntl
->
http_request
().
GetHeader
(
common
->
GRPC_ACCEPT_ENCODING
);
return
(
encodings
&&
encodings
->
find
(
common
->
GZIP
)
!=
std
::
string
::
npos
)
||
(
grpc_encodings
&&
grpc_encodings
->
find
(
common
->
GZIP
)
!=
std
::
string
::
npos
);
}
}
class
HttpResponseSender
{
class
HttpResponseSender
{
...
@@ -692,6 +685,20 @@ HttpResponseSender::~HttpResponseSender() {
...
@@ -692,6 +685,20 @@ HttpResponseSender::~HttpResponseSender() {
res_header
->
set_version
(
req_header
->
major_version
(),
res_header
->
set_version
(
req_header
->
major_version
(),
req_header
->
minor_version
());
req_header
->
minor_version
());
const
std
::
string
*
content_type_str
=
&
res_header
->
content_type
();
if
(
content_type_str
->
empty
())
{
// Use request's content_type if response's is not set.
content_type_str
=
&
req_header
->
content_type
();
res_header
->
set_content_type
(
*
content_type_str
);
}
// Notice that HTTP1 can have a header named `grpc-encoding' as well
// which should be treated as an user-defined header and ignored by
// the framework.
bool
is_grpc_ct
=
false
;
const
HttpContentType
content_type
=
ParseContentType
(
*
content_type_str
,
&
is_grpc_ct
);
const
bool
is_http2
=
req_header
->
is_http2
();
const
bool
is_grpc
=
(
is_http2
&&
is_grpc_ct
);
// Convert response to json/proto if needed.
// Convert response to json/proto if needed.
// Notice: Not check res->IsInitialized() which should be checked in the
// Notice: Not check res->IsInitialized() which should be checked in the
// conversion function.
// conversion function.
...
@@ -704,20 +711,8 @@ HttpResponseSender::~HttpResponseSender() {
...
@@ -704,20 +711,8 @@ HttpResponseSender::~HttpResponseSender() {
// ^ pb response in failed RPC is undefined, no need to convert.
// ^ pb response in failed RPC is undefined, no need to convert.
butil
::
IOBufAsZeroCopyOutputStream
wrapper
(
&
cntl
->
response_attachment
());
butil
::
IOBufAsZeroCopyOutputStream
wrapper
(
&
cntl
->
response_attachment
());
const
std
::
string
*
content_type_str
=
&
res_header
->
content_type
();
if
(
content_type
==
HTTP_CONTENT_PROTO
)
{
if
(
content_type_str
->
empty
())
{
if
(
!
res
->
SerializeToZeroCopyStream
(
&
wrapper
))
{
content_type_str
=
&
req_header
->
content_type
();
}
const
HttpContentType
content_type
=
ParseContentType
(
*
content_type_str
);
if
(
content_type
==
HTTP_CONTENT_PROTO
||
content_type
==
HTTP_CONTENT_GRPC
)
{
if
(
res
->
SerializeToZeroCopyStream
(
&
wrapper
))
{
// Set content-type if user did not
if
(
res_header
->
content_type
().
empty
())
{
res_header
->
set_content_type
((
content_type
==
HTTP_CONTENT_PROTO
)
?
common
->
CONTENT_TYPE_PROTO
:
common
->
CONTENT_TYPE_GRPC
);
}
}
else
{
cntl
->
SetFailed
(
ERESPONSE
,
"Fail to serialize %s"
,
res
->
GetTypeName
().
c_str
());
cntl
->
SetFailed
(
ERESPONSE
,
"Fail to serialize %s"
,
res
->
GetTypeName
().
c_str
());
}
}
}
else
{
}
else
{
...
@@ -728,12 +723,7 @@ HttpResponseSender::~HttpResponseSender() {
...
@@ -728,12 +723,7 @@ HttpResponseSender::~HttpResponseSender() {
opt
.
enum_option
=
(
FLAGS_pb_enum_as_number
opt
.
enum_option
=
(
FLAGS_pb_enum_as_number
?
json2pb
::
OUTPUT_ENUM_BY_NUMBER
?
json2pb
::
OUTPUT_ENUM_BY_NUMBER
:
json2pb
::
OUTPUT_ENUM_BY_NAME
);
:
json2pb
::
OUTPUT_ENUM_BY_NAME
);
if
(
json2pb
::
ProtoMessageToJson
(
*
res
,
&
wrapper
,
opt
,
&
err
))
{
if
(
!
json2pb
::
ProtoMessageToJson
(
*
res
,
&
wrapper
,
opt
,
&
err
))
{
// Set content-type if user did not
if
(
res_header
->
content_type
().
empty
())
{
res_header
->
set_content_type
(
common
->
CONTENT_TYPE_JSON
);
}
}
else
{
cntl
->
SetFailed
(
ERESPONSE
,
"Fail to convert response to json, %s"
,
err
.
c_str
());
cntl
->
SetFailed
(
ERESPONSE
,
"Fail to convert response to json, %s"
,
err
.
c_str
());
}
}
}
}
...
@@ -752,7 +742,7 @@ HttpResponseSender::~HttpResponseSender() {
...
@@ -752,7 +742,7 @@ HttpResponseSender::~HttpResponseSender() {
// or the server sent a Connection: close response header. If such a
// or the server sent a Connection: close response header. If such a
// response header exists, the client must close its end of the connection
// response header exists, the client must close its end of the connection
// after receiving the response.
// after receiving the response.
if
(
!
req_header
->
is_http2
()
)
{
if
(
!
is_http2
)
{
const
std
::
string
*
res_conn
=
res_header
->
GetHeader
(
common
->
CONNECTION
);
const
std
::
string
*
res_conn
=
res_header
->
GetHeader
(
common
->
CONNECTION
);
if
(
res_conn
==
NULL
||
strcasecmp
(
res_conn
->
c_str
(),
"close"
)
!=
0
)
{
if
(
res_conn
==
NULL
||
strcasecmp
(
res_conn
->
c_str
(),
"close"
)
!=
0
)
{
const
std
::
string
*
req_conn
=
const
std
::
string
*
req_conn
=
...
@@ -770,28 +760,31 @@ HttpResponseSender::~HttpResponseSender() {
...
@@ -770,28 +760,31 @@ HttpResponseSender::~HttpResponseSender() {
}
}
}
// else user explicitly set Connection:close, clients of
}
// else user explicitly set Connection:close, clients of
// HTTP 1.1/1.0/0.9 should all close the connection.
// HTTP 1.1/1.0/0.9 should all close the connection.
}
else
if
(
is_grpc
)
{
// status code is always 200 according to grpc protocol
res_header
->
set_status_code
(
HTTP_STATUS_OK
);
}
}
bool
grpc_compressed
=
false
;
bool
grpc_compressed
=
false
;
bool
grpc_protocol
=
ParseContentType
(
req_header
->
content_type
())
==
HTTP_CONTENT_GRPC
;
if
(
cntl
->
Failed
())
{
if
(
cntl
->
Failed
())
{
// Set status-code with default value(converted from error code)
// if user did not set it.
if
(
res_header
->
status_code
()
==
HTTP_STATUS_OK
)
{
res_header
->
set_status_code
(
ErrorCodeToStatusCode
(
cntl
->
ErrorCode
()));
}
// Fill ErrorCode into header
res_header
->
SetHeader
(
common
->
ERROR_CODE
,
butil
::
string_printf
(
"%d"
,
cntl
->
ErrorCode
()));
// Fill body with ErrorText.
// user may compress the output and change content-encoding. However
// body is error-text right now, remove the header.
res_header
->
RemoveHeader
(
common
->
CONTENT_ENCODING
);
res_header
->
set_content_type
(
common
->
CONTENT_TYPE_TEXT
);
cntl
->
response_attachment
().
clear
();
cntl
->
response_attachment
().
clear
();
cntl
->
response_attachment
().
append
(
cntl
->
ErrorText
());
if
(
!
is_grpc
)
{
// Set status-code with default value(converted from error code)
// if user did not set it.
if
(
res_header
->
status_code
()
==
HTTP_STATUS_OK
)
{
res_header
->
set_status_code
(
ErrorCodeToStatusCode
(
cntl
->
ErrorCode
()));
}
// Fill ErrorCode into header
res_header
->
SetHeader
(
common
->
ERROR_CODE
,
butil
::
string_printf
(
"%d"
,
cntl
->
ErrorCode
()));
// Fill body with ErrorText.
// user may compress the output and change content-encoding. However
// body is error-text right now, remove the header.
res_header
->
RemoveHeader
(
common
->
CONTENT_ENCODING
);
res_header
->
set_content_type
(
common
->
CONTENT_TYPE_TEXT
);
cntl
->
response_attachment
().
append
(
cntl
->
ErrorText
());
}
}
else
if
(
cntl
->
has_progressive_writer
())
{
}
else
if
(
cntl
->
has_progressive_writer
())
{
// Transfer-Encoding is supported since HTTP/1.1
// Transfer-Encoding is supported since HTTP/1.1
if
(
res_header
->
major_version
()
<
2
&&
!
res_header
->
before_http_1_1
())
{
if
(
res_header
->
major_version
()
<
2
&&
!
res_header
->
before_http_1_1
())
{
...
@@ -803,57 +796,29 @@ HttpResponseSender::~HttpResponseSender() {
...
@@ -803,57 +796,29 @@ HttpResponseSender::~HttpResponseSender() {
" ignored when CreateProgressiveAttachment() was called"
;
" ignored when CreateProgressiveAttachment() was called"
;
}
}
// not set_content to enable chunked mode.
// not set_content to enable chunked mode.
}
else
{
}
else
if
(
cntl
->
response_compress_type
()
==
COMPRESS_TYPE_GZIP
)
{
if
(
cntl
->
response_compress_type
()
==
COMPRESS_TYPE_GZIP
)
{
const
size_t
response_size
=
cntl
->
response_attachment
().
size
();
const
size_t
response_size
=
cntl
->
response_attachment
().
size
();
if
(
response_size
>=
(
size_t
)
FLAGS_http_body_compress_threshold
if
(
response_size
>=
(
size_t
)
FLAGS_http_body_compress_threshold
&&
(
is_http2
||
SupportGzip
(
cntl
)))
{
&&
SupportGzip
(
cntl
))
{
TRACEPRINTF
(
"Compressing response=%lu"
,
(
unsigned
long
)
response_size
);
TRACEPRINTF
(
"Compressing response=%lu"
,
(
unsigned
long
)
response_size
);
butil
::
IOBuf
tmpbuf
;
butil
::
IOBuf
tmpbuf
;
if
(
GzipCompress
(
cntl
->
response_attachment
(),
&
tmpbuf
,
NULL
))
{
if
(
GzipCompress
(
cntl
->
response_attachment
(),
&
tmpbuf
,
NULL
))
{
cntl
->
response_attachment
().
swap
(
tmpbuf
);
cntl
->
response_attachment
().
swap
(
tmpbuf
);
if
(
is_grpc
)
{
if
(
grpc_protocol
)
{
grpc_compressed
=
true
;
grpc_compressed
=
true
;
res_header
->
SetHeader
(
common
->
GRPC_ENCODING
,
common
->
GZIP
);
res_header
->
SetHeader
(
common
->
GRPC_ENCODING
,
common
->
GZIP
);
}
else
{
res_header
->
SetHeader
(
common
->
CONTENT_ENCODING
,
common
->
GZIP
);
}
}
else
{
}
else
{
LOG
(
ERROR
)
<<
"Fail to gzip the http response, skip compression."
;
res_header
->
SetHeader
(
common
->
CONTENT_ENCODING
,
common
->
GZIP
)
;
}
}
}
}
else
{
LOG_IF
(
ERROR
,
cntl
->
response_compress_type
()
!=
COMPRESS_TYPE_NONE
)
<<
"Unknown compress_type="
<<
cntl
->
response_compress_type
()
<<
", skip compression."
;
}
}
if
(
grpc_protocol
)
{
// status code is always 200 according to grpc protocol
res_header
->
set_status_code
(
HTTP_STATUS_OK
);
res_header
->
set_content_type
(
common
->
CONTENT_TYPE_GRPC
);
// always tell client gzip support
// TODO(zhujiashun): add zlib and snappy?
res_header
->
SetHeader
(
common
->
GRPC_ACCEPT_ENCODING
,
common
->
IDENTITY
+
","
+
common
->
GZIP
);
if
(
!
cntl
->
Failed
())
{
// Encode Length-Prefixed-Message
butil
::
IOBuf
tmp_buf
;
// Compressed-Flag as 0 / 1, encoded as 1 byte unsigned integer
if
(
grpc_compressed
)
{
tmp_buf
.
append
(
"
\1
"
,
1
);
}
else
{
}
else
{
tmp_buf
.
append
(
"
\0
"
,
1
)
;
LOG
(
ERROR
)
<<
"Fail to gzip the http response, skip compression."
;
}
}
char
size_buf
[
4
];
WriteBigEndian4Bytes
(
size_buf
,
cntl
->
response_attachment
().
size
());
tmp_buf
.
append
(
size_buf
,
4
);
tmp_buf
.
append
(
cntl
->
response_attachment
());
cntl
->
response_attachment
().
swap
(
tmp_buf
);
}
else
{
cntl
->
response_attachment
().
clear
();
}
}
}
else
{
// TODO(gejun): Support snappy (grpc)
LOG_IF
(
ERROR
,
cntl
->
response_compress_type
()
!=
COMPRESS_TYPE_NONE
)
<<
"Unknown compress_type="
<<
cntl
->
response_compress_type
()
<<
", skip compression."
;
}
}
int
rc
=
-
1
;
int
rc
=
-
1
;
...
@@ -861,18 +826,20 @@ HttpResponseSender::~HttpResponseSender() {
...
@@ -861,18 +826,20 @@ HttpResponseSender::~HttpResponseSender() {
// users to set max_concurrency.
// users to set max_concurrency.
Socket
::
WriteOptions
wopt
;
Socket
::
WriteOptions
wopt
;
wopt
.
ignore_eovercrowded
=
true
;
wopt
.
ignore_eovercrowded
=
true
;
if
(
req_header
->
is_http2
())
{
if
(
is_http2
)
{
if
(
is_grpc
)
{
// Append compressed and length before body
AddGrpcPrefix
(
&
cntl
->
response_attachment
(),
grpc_compressed
);
}
SocketMessagePtr
<
H2UnsentResponse
>
h2_response
(
SocketMessagePtr
<
H2UnsentResponse
>
h2_response
(
H2UnsentResponse
::
New
(
cntl
,
_h2_stream_id
,
grpc_protocol
));
H2UnsentResponse
::
New
(
cntl
,
_h2_stream_id
,
is_grpc
));
if
(
h2_response
==
NULL
)
{
if
(
h2_response
==
NULL
)
{
LOG
(
ERROR
)
<<
"Fail to make http2 response"
;
LOG
(
ERROR
)
<<
"Fail to make http2 response"
;
errno
=
EINVAL
;
errno
=
EINVAL
;
rc
=
-
1
;
rc
=
-
1
;
}
else
{
}
else
{
if
(
FLAGS_http_verbose
)
{
if
(
FLAGS_http_verbose
)
{
butil
::
IOBuf
desc
;
std
::
cerr
<<
*
h2_response
<<
std
::
endl
;
h2_response
->
Describe
(
&
desc
);
std
::
cerr
<<
desc
<<
std
::
endl
;
}
}
if
(
span
)
{
if
(
span
)
{
span
->
set_response_size
(
h2_response
->
EstimatedByteSize
());
span
->
set_response_size
(
h2_response
->
EstimatedByteSize
());
...
@@ -885,7 +852,7 @@ HttpResponseSender::~HttpResponseSender() {
...
@@ -885,7 +852,7 @@ HttpResponseSender::~HttpResponseSender() {
content
=
&
cntl
->
response_attachment
();
content
=
&
cntl
->
response_attachment
();
}
}
butil
::
IOBuf
res_buf
;
butil
::
IOBuf
res_buf
;
Serialize
HttpResponse
(
&
res_buf
,
res_header
,
content
);
MakeRaw
HttpResponse
(
&
res_buf
,
res_header
,
content
);
if
(
FLAGS_http_verbose
)
{
if
(
FLAGS_http_verbose
)
{
PrintMessage
(
res_buf
,
false
,
!!
content
);
PrintMessage
(
res_buf
,
false
,
!!
content
);
}
}
...
@@ -1140,7 +1107,7 @@ ParseResult ParseHttpMessage(butil::IOBuf *source, Socket *socket,
...
@@ -1140,7 +1107,7 @@ ParseResult ParseHttpMessage(butil::IOBuf *source, Socket *socket,
butil
::
IOBuf
bad_req
;
butil
::
IOBuf
bad_req
;
HttpHeader
header
;
HttpHeader
header
;
header
.
set_status_code
(
HTTP_STATUS_BAD_REQUEST
);
header
.
set_status_code
(
HTTP_STATUS_BAD_REQUEST
);
Serialize
HttpRequest
(
&
bad_req
,
&
header
,
socket
->
remote_side
(),
NULL
);
MakeRaw
HttpRequest
(
&
bad_req
,
&
header
,
socket
->
remote_side
(),
NULL
);
Socket
::
WriteOptions
wopt
;
Socket
::
WriteOptions
wopt
;
wopt
.
ignore_eovercrowded
=
true
;
wopt
.
ignore_eovercrowded
=
true
;
socket
->
Write
(
&
bad_req
,
&
wopt
);
socket
->
Write
(
&
bad_req
,
&
wopt
);
...
@@ -1228,17 +1195,6 @@ void ProcessHttpRequest(InputMessageBase *msg) {
...
@@ -1228,17 +1195,6 @@ void ProcessHttpRequest(InputMessageBase *msg) {
imsg_guard
->
header
().
Swap
(
req_header
);
imsg_guard
->
header
().
Swap
(
req_header
);
butil
::
IOBuf
&
req_body
=
imsg_guard
->
body
();
butil
::
IOBuf
&
req_body
=
imsg_guard
->
body
();
char
grpc_compressed
=
false
;
if
(
ParseContentType
(
req_header
.
content_type
())
==
HTTP_CONTENT_GRPC
&&
!
req_body
.
empty
())
{
/* 4 is the size of grpc Message-Length in Length-Prefixed-Message*/
char
buf
[
4
];
req_body
.
cut1
(
&
grpc_compressed
);
req_body
.
cutn
(
buf
,
4
);
int
message_length
=
ReadBigEndian4Bytes
(
buf
);
CHECK
((
size_t
)
message_length
==
req_body
.
length
());
}
butil
::
EndPoint
user_addr
;
butil
::
EndPoint
user_addr
;
if
(
!
GetUserAddressFromHeader
(
req_header
,
&
user_addr
))
{
if
(
!
GetUserAddressFromHeader
(
req_header
,
&
user_addr
))
{
user_addr
=
socket
->
remote_side
();
user_addr
=
socket
->
remote_side
();
...
@@ -1302,7 +1258,7 @@ void ProcessHttpRequest(InputMessageBase *msg) {
...
@@ -1302,7 +1258,7 @@ void ProcessHttpRequest(InputMessageBase *msg) {
span
->
set_remote_side
(
user_addr
);
span
->
set_remote_side
(
user_addr
);
span
->
set_received_us
(
msg
->
received_us
());
span
->
set_received_us
(
msg
->
received_us
());
span
->
set_start_parse_us
(
start_parse_us
);
span
->
set_start_parse_us
(
start_parse_us
);
span
->
set_protocol
(
req_header
.
is_http2
()
?
PROTOCOL_HTTP2
:
PROTOCOL_HTTP
);
span
->
set_protocol
(
is_http2
?
PROTOCOL_HTTP2
:
PROTOCOL_HTTP
);
span
->
set_request_size
(
imsg_guard
->
parsed_length
());
span
->
set_request_size
(
imsg_guard
->
parsed_length
());
}
}
...
@@ -1391,7 +1347,7 @@ void ProcessHttpRequest(InputMessageBase *msg) {
...
@@ -1391,7 +1347,7 @@ void ProcessHttpRequest(InputMessageBase *msg) {
" internal network"
,
server
->
options
().
internal_port
);
" internal network"
,
server
->
options
().
internal_port
);
return
;
return
;
}
}
google
::
protobuf
::
Service
*
svc
=
sp
->
service
;
google
::
protobuf
::
Service
*
svc
=
sp
->
service
;
const
google
::
protobuf
::
MethodDescriptor
*
method
=
sp
->
method
;
const
google
::
protobuf
::
MethodDescriptor
*
method
=
sp
->
method
;
accessor
.
set_method
(
method
);
accessor
.
set_method
(
method
);
...
@@ -1420,13 +1376,31 @@ void ProcessHttpRequest(InputMessageBase *msg) {
...
@@ -1420,13 +1376,31 @@ void ProcessHttpRequest(InputMessageBase *msg) {
return
;
return
;
}
// else all fields of the request are optional.
}
// else all fields of the request are optional.
}
else
{
}
else
{
const
std
::
string
*
encoding
=
bool
is_grpc_ct
=
false
;
req_header
.
GetHeader
(
common
->
CONTENT_ENCODING
);
const
HttpContentType
content_type
=
const
std
::
string
*
grpc_encoding
=
ParseContentType
(
req_header
.
content_type
(),
&
is_grpc_ct
);
req_header
.
GetHeader
(
common
->
GRPC_ENCODING
);
const
std
::
string
*
encoding
=
NULL
;
if
((
encoding
!=
NULL
&&
*
encoding
==
common
->
GZIP
)
||
if
(
is_http2
)
{
(
grpc_compressed
&&
grpc_encoding
!=
NULL
&&
*
grpc_encoding
==
if
(
is_grpc_ct
)
{
common
->
GZIP
))
{
bool
grpc_compressed
=
false
;
if
(
!
RemoveGrpcPrefix
(
&
req_body
,
&
grpc_compressed
))
{
cntl
->
SetFailed
(
ERESPONSE
,
"Invalid gRPC response"
);
return
;
}
if
(
grpc_compressed
)
{
encoding
=
req_header
.
GetHeader
(
common
->
GRPC_ENCODING
);
if
(
encoding
==
NULL
)
{
cntl
->
SetFailed
(
EREQUEST
,
"Fail to find header `grpc-encoding'"
" in compressed gRPC request"
);
return
;
}
}
}
}
else
{
encoding
=
req_header
.
GetHeader
(
common
->
CONTENT_ENCODING
);
}
if
(
encoding
!=
NULL
&&
*
encoding
==
common
->
GZIP
)
{
TRACEPRINTF
(
"Decompressing request=%lu"
,
TRACEPRINTF
(
"Decompressing request=%lu"
,
(
unsigned
long
)
req_body
.
size
());
(
unsigned
long
)
req_body
.
size
());
butil
::
IOBuf
uncompressed
;
butil
::
IOBuf
uncompressed
;
...
@@ -1436,8 +1410,7 @@ void ProcessHttpRequest(InputMessageBase *msg) {
...
@@ -1436,8 +1410,7 @@ void ProcessHttpRequest(InputMessageBase *msg) {
}
}
req_body
.
swap
(
uncompressed
);
req_body
.
swap
(
uncompressed
);
}
}
HttpContentType
content_type
=
ParseContentType
(
req_header
.
content_type
());
if
(
content_type
==
HTTP_CONTENT_PROTO
)
{
if
(
content_type
==
HTTP_CONTENT_PROTO
||
content_type
==
HTTP_CONTENT_GRPC
)
{
if
(
!
ParsePbFromIOBuf
(
req
,
req_body
))
{
if
(
!
ParsePbFromIOBuf
(
req
,
req_body
))
{
cntl
->
SetFailed
(
EREQUEST
,
"Fail to parse http body as %s"
,
cntl
->
SetFailed
(
EREQUEST
,
"Fail to parse http body as %s"
,
req
->
GetDescriptor
()
->
full_name
().
c_str
());
req
->
GetDescriptor
()
->
full_name
().
c_str
());
...
...
src/brpc/policy/http_rpc_protocol.h
View file @
4a0927af
...
@@ -41,7 +41,6 @@ struct CommonStrings {
...
@@ -41,7 +41,6 @@ struct CommonStrings {
std
::
string
ACCEPT_ENCODING
;
std
::
string
ACCEPT_ENCODING
;
std
::
string
CONTENT_ENCODING
;
std
::
string
CONTENT_ENCODING
;
std
::
string
CONTENT_LENGTH
;
std
::
string
CONTENT_LENGTH
;
std
::
string
IDENTITY
;
std
::
string
GZIP
;
std
::
string
GZIP
;
std
::
string
CONNECTION
;
std
::
string
CONNECTION
;
std
::
string
KEEP_ALIVE
;
std
::
string
KEEP_ALIVE
;
...
@@ -69,6 +68,7 @@ struct CommonStrings {
...
@@ -69,6 +68,7 @@ struct CommonStrings {
std
::
string
TRAILERS
;
std
::
string
TRAILERS
;
std
::
string
GRPC_ENCODING
;
std
::
string
GRPC_ENCODING
;
std
::
string
GRPC_ACCEPT_ENCODING
;
std
::
string
GRPC_ACCEPT_ENCODING
;
std
::
string
GRPC_ACCEPT_ENCODING_VALUE
;
std
::
string
GRPC_STATUS
;
std
::
string
GRPC_STATUS
;
std
::
string
GRPC_MESSAGE
;
std
::
string
GRPC_MESSAGE
;
...
@@ -77,8 +77,8 @@ struct CommonStrings {
...
@@ -77,8 +77,8 @@ struct CommonStrings {
// Used in UT.
// Used in UT.
class
HttpContext
:
public
ReadableProgressiveAttachment
class
HttpContext
:
public
ReadableProgressiveAttachment
,
public
InputMessageBase
,
public
InputMessageBase
,
public
HttpMessage
{
,
public
HttpMessage
{
public
:
public
:
HttpContext
(
bool
read_body_progressively
=
false
)
HttpContext
(
bool
read_body_progressively
=
false
)
:
InputMessageBase
()
:
InputMessageBase
()
...
@@ -138,13 +138,14 @@ enum HttpContentType {
...
@@ -138,13 +138,14 @@ enum HttpContentType {
HTTP_CONTENT_OTHERS
=
0
,
HTTP_CONTENT_OTHERS
=
0
,
HTTP_CONTENT_JSON
=
1
,
HTTP_CONTENT_JSON
=
1
,
HTTP_CONTENT_PROTO
=
2
,
HTTP_CONTENT_PROTO
=
2
,
HTTP_CONTENT_GRPC
=
3
};
};
HttpContentType
ParseContentType
(
butil
::
StringPiece
content_type
);
// Parse from the textual content type. One type may have more than one literals.
// Returns a numerical type. *is_grpc_ct is set to true if the content-type is
// set by gRPC.
HttpContentType
ParseContentType
(
butil
::
StringPiece
content_type
,
bool
*
is_grpc_ct
);
}
// namespace policy
}
// namespace policy
}
// namespace brpc
}
// namespace brpc
#endif // BRPC_POLICY_HTTP_RPC_PROTOCOL_H
#endif // BRPC_POLICY_HTTP_RPC_PROTOCOL_H
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment