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
691b8a15
Commit
691b8a15
authored
Aug 06, 2017
by
gejun
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
patch svn r34971
Change-Id: I2dab12ac61990359fc34d04c42aeb23aa92960eb
parent
456243ee
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
187 additions
and
53 deletions
+187
-53
http_message.cpp
brpc/details/http_message.cpp
+36
-35
http_message.h
brpc/details/http_message.h
+4
-2
http_rpc_protocol.cpp
brpc/policy/http_rpc_protocol.cpp
+3
-3
uri.cpp
brpc/uri.cpp
+6
-2
uri.h
brpc/uri.h
+5
-4
brpc_channel_unittest.cpp
test/brpc_channel_unittest.cpp
+57
-0
brpc_http_message_unittest.cpp
test/brpc_http_message_unittest.cpp
+70
-1
brpc_uri_unittest.cpp
test/brpc_uri_unittest.cpp
+6
-6
No files found.
brpc/details/http_message.cpp
View file @
691b8a15
...
...
@@ -518,19 +518,19 @@ std::ostream& operator<<(std::ostream& os, const http_parser& parser) {
// | extension-method
// extension-method = token
void
SerializeHttpRequest
(
base
::
IOBuf
*
request
,
const
HttpHeader
&
header
,
HttpHeader
*
h
,
const
base
::
EndPoint
&
remote_side
,
const
base
::
IOBuf
*
content
)
{
base
::
IOBufBuilder
os
;
const
URI
&
uri
=
header
.
uri
()
;
os
<<
HttpMethod2Str
(
header
.
method
())
<<
' '
;
// note: hide host if possible because host is a field in
header.
uri
.
Print
(
os
,
false
/*note*/
);
os
<<
" HTTP/"
<<
header
.
major_version
()
<<
'.'
<<
header
.
minor_version
()
<<
BRPC_CRLF
;
if
(
header
.
method
()
!=
HTTP_METHOD_GET
)
{
os
<<
HttpMethod2Str
(
h
->
method
())
<<
' '
;
const
URI
&
uri
=
h
->
uri
()
;
uri
.
PrintWithoutHost
(
os
);
// host is sent by "Host"
header.
os
<<
" HTTP/"
<<
h
->
major_version
()
<<
'.'
<<
h
->
minor_version
()
<<
BRPC_CRLF
;
if
(
h
->
method
()
!=
HTTP_METHOD_GET
)
{
h
->
RemoveHeader
(
"Content-Length"
);
// Never use "Content-Length" set by user.
os
<<
"Content-Length:
"
<<
(
content
?
content
->
length
()
:
0
)
os
<<
"Content-Length:"
<<
(
content
?
content
->
length
()
:
0
)
<<
BRPC_CRLF
;
}
//rfc 7230#section-5.4:
...
...
@@ -542,8 +542,8 @@ void SerializeHttpRequest(base::IOBuf* request,
//the request-target consists of only the host name and port number of
//the tunnel destination, seperated by a colon. For example,
//Host: server.example.com:80
if
(
h
eader
.
GetHeader
(
"host"
)
==
NULL
)
{
os
<<
"Host:
"
;
if
(
h
->
GetHeader
(
"host"
)
==
NULL
)
{
os
<<
"Host:"
;
if
(
!
uri
.
host
().
empty
())
{
os
<<
uri
.
host
();
if
(
uri
.
port
()
>=
0
)
{
...
...
@@ -554,40 +554,40 @@ void SerializeHttpRequest(base::IOBuf* request,
}
os
<<
BRPC_CRLF
;
}
if
(
!
h
eader
.
content_type
().
empty
())
{
os
<<
"Content-Type:
"
<<
header
.
content_type
()
if
(
!
h
->
content_type
().
empty
())
{
os
<<
"Content-Type:
"
<<
h
->
content_type
()
<<
BRPC_CRLF
;
}
for
(
HttpHeader
::
HeaderIterator
it
=
h
eader
.
HeaderBegin
();
it
!=
h
eader
.
HeaderEnd
();
++
it
)
{
os
<<
it
->
first
<<
": "
<<
it
->
second
<<
BRPC_CRLF
;
for
(
HttpHeader
::
HeaderIterator
it
=
h
->
HeaderBegin
();
it
!=
h
->
HeaderEnd
();
++
it
)
{
os
<<
it
->
first
<<
':'
<<
it
->
second
<<
BRPC_CRLF
;
}
if
(
h
eader
.
GetHeader
(
"Accept"
)
==
NULL
)
{
os
<<
"Accept:
*/*"
BRPC_CRLF
;
if
(
h
->
GetHeader
(
"Accept"
)
==
NULL
)
{
os
<<
"Accept:*/*"
BRPC_CRLF
;
}
// The fake "curl" user-agent may let servers return plain-text results.
if
(
h
eader
.
GetHeader
(
"User-Agent"
)
==
NULL
)
{
os
<<
"User-Agent:
baidu-rpc/1.0 curl/7.0"
BRPC_CRLF
;
if
(
h
->
GetHeader
(
"User-Agent"
)
==
NULL
)
{
os
<<
"User-Agent:baidu-rpc/1.0 curl/7.0"
BRPC_CRLF
;
}
const
std
::
string
&
user_info
=
h
eader
.
uri
().
user_info
();
if
(
!
user_info
.
empty
()
&&
h
eader
.
GetHeader
(
"Authorization"
)
==
NULL
)
{
const
std
::
string
&
user_info
=
h
->
uri
().
user_info
();
if
(
!
user_info
.
empty
()
&&
h
->
GetHeader
(
"Authorization"
)
==
NULL
)
{
// NOTE: just assume user_info is well formatted, namely
// "<user_name>:<password>". Users are very unlikely to add extra
// characters in this part and even if users did, most of them are
// invalid and rejected by http_parser_parse_url().
std
::
string
encoded_user_info
;
base
::
Base64Encode
(
user_info
,
&
encoded_user_info
);
os
<<
"Authorization:
Basic "
<<
encoded_user_info
<<
BRPC_CRLF
;
os
<<
"Authorization:Basic "
<<
encoded_user_info
<<
BRPC_CRLF
;
}
os
<<
BRPC_CRLF
;
// CRLF before content
os
.
move_to
(
*
request
);
if
(
h
eader
.
method
()
!=
HTTP_METHOD_GET
&&
content
)
{
if
(
h
->
method
()
!=
HTTP_METHOD_GET
&&
content
)
{
request
->
append
(
*
content
);
}
}
// Response format
// Response
= Status-Line ; Section 6.1
// Response = Status-Line ; Section 6.1
// *(( general-header ; Section 4.5
// | response-header ; Section 6.2
// | entity-header ) CRLF) ; Section 7.1
...
...
@@ -596,25 +596,26 @@ void SerializeHttpRequest(base::IOBuf* request,
//
// Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF
void
SerializeHttpResponse
(
base
::
IOBuf
*
response
,
const
HttpHeader
&
header
,
HttpHeader
*
h
,
base
::
IOBuf
*
content
)
{
base
::
IOBufBuilder
os
;
os
<<
"HTTP/"
<<
h
eader
.
major_version
()
<<
'.'
<<
h
eader
.
minor_version
()
<<
' '
<<
header
.
status_code
()
<<
' '
<<
h
eader
.
reason_phrase
()
<<
BRPC_CRLF
;
os
<<
"HTTP/"
<<
h
->
major_version
()
<<
'.'
<<
h
->
minor_version
()
<<
' '
<<
h
->
status_code
()
<<
' '
<<
h
->
reason_phrase
()
<<
BRPC_CRLF
;
if
(
content
)
{
h
->
RemoveHeader
(
"Content-Length"
);
// Never use "Content-Length" set by user.
// Always set Content-Length since lighttpd requires the header to be
// set to 0 for empty content.
os
<<
"Content-Length:
"
<<
content
->
length
()
<<
BRPC_CRLF
;
os
<<
"Content-Length:"
<<
content
->
length
()
<<
BRPC_CRLF
;
}
if
(
!
h
eader
.
content_type
().
empty
())
{
os
<<
"Content-Type:
"
<<
header
.
content_type
()
if
(
!
h
->
content_type
().
empty
())
{
os
<<
"Content-Type:
"
<<
h
->
content_type
()
<<
BRPC_CRLF
;
}
for
(
HttpHeader
::
HeaderIterator
it
=
h
eader
.
HeaderBegin
();
it
!=
h
eader
.
HeaderEnd
();
++
it
)
{
os
<<
it
->
first
<<
": "
<<
it
->
second
<<
BRPC_CRLF
;
for
(
HttpHeader
::
HeaderIterator
it
=
h
->
HeaderBegin
();
it
!=
h
->
HeaderEnd
();
++
it
)
{
os
<<
it
->
first
<<
':'
<<
it
->
second
<<
BRPC_CRLF
;
}
os
<<
BRPC_CRLF
;
// CRLF before content
os
.
move_to
(
*
response
);
...
...
brpc/details/http_message.h
View file @
691b8a15
...
...
@@ -107,17 +107,19 @@ protected:
std
::
ostream
&
operator
<<
(
std
::
ostream
&
os
,
const
http_parser
&
parser
);
// Serialize a http request.
// header: may be modified in some cases
// remote_side: used when "Host" is absent
// content: could be NULL.
void
SerializeHttpRequest
(
base
::
IOBuf
*
request
,
const
HttpHeader
&
header
,
HttpHeader
*
header
,
const
base
::
EndPoint
&
remote_side
,
const
base
::
IOBuf
*
content
);
// Serialize a http response.
// header: may be modified in some cases
// content: cleared after usage. could be NULL.
void
SerializeHttpResponse
(
base
::
IOBuf
*
response
,
const
HttpHeader
&
header
,
HttpHeader
*
header
,
base
::
IOBuf
*
content
);
}
// namespace brpc
...
...
brpc/policy/http_rpc_protocol.cpp
View file @
691b8a15
...
...
@@ -504,7 +504,7 @@ void PackHttpRequest(base::IOBuf* buf,
// may not echo back this field. But we send it anyway.
accessor
.
get_sending_socket
()
->
set_correlation_id
(
correlation_id
);
SerializeHttpRequest
(
buf
,
*
header
,
cntl
->
remote_side
(),
SerializeHttpRequest
(
buf
,
header
,
cntl
->
remote_side
(),
&
cntl
->
request_attachment
());
if
(
FLAGS_http_verbose
)
{
PrintMessage
(
*
buf
,
true
,
true
);
...
...
@@ -705,7 +705,7 @@ static void SendHttpResponse(Controller *cntl,
content
=
&
cntl
->
response_attachment
();
}
base
::
IOBuf
res_buf
;
SerializeHttpResponse
(
&
res_buf
,
*
res_header
,
content
);
SerializeHttpResponse
(
&
res_buf
,
res_header
,
content
);
if
(
FLAGS_http_verbose
)
{
PrintMessage
(
res_buf
,
false
,
!!
content
);
}
...
...
@@ -969,7 +969,7 @@ ParseResult ParseHttpMessage(base::IOBuf *source, Socket *socket,
base
::
IOBuf
bad_req
;
HttpHeader
header
;
header
.
set_status_code
(
HTTP_STATUS_BAD_REQUEST
);
SerializeHttpRequest
(
&
bad_req
,
header
,
socket
->
remote_side
(),
NULL
);
SerializeHttpRequest
(
&
bad_req
,
&
header
,
socket
->
remote_side
(),
NULL
);
Socket
::
WriteOptions
wopt
;
wopt
.
ignore_eovercrowded
=
true
;
socket
->
Write
(
&
bad_req
,
&
wopt
);
...
...
brpc/uri.cpp
View file @
691b8a15
...
...
@@ -266,8 +266,8 @@ int ParseHostAndPortFromURL(const char* url, std::string* host_out,
return
0
;
}
void
URI
::
Print
(
std
::
ostream
&
os
,
bool
always_show_host
)
const
{
if
(
!
_host
.
empty
()
&&
always_show_host
)
{
void
URI
::
Print
(
std
::
ostream
&
os
)
const
{
if
(
!
_host
.
empty
())
{
if
(
!
_schema
.
empty
())
{
os
<<
_schema
<<
"://"
;
}
else
{
...
...
@@ -279,6 +279,10 @@ void URI::Print(std::ostream& os, bool always_show_host) const {
os
<<
':'
<<
_port
;
}
}
PrintWithoutHost
(
os
);
}
void
URI
::
PrintWithoutHost
(
std
::
ostream
&
os
)
const
{
if
(
_path
.
empty
())
{
// According to rfc2616#section-5.1.2, the absolute path
// cannot be empty; if none is present in the original URI, it MUST
...
...
brpc/uri.h
View file @
691b8a15
...
...
@@ -111,9 +111,10 @@ public:
// #queries
size_t
QueryCount
()
const
{
return
get_query_map
().
size
();
}
// Print this URI. If `always_show_host' is false, host:port will
// be hidden is there's no authority part.
void
Print
(
std
::
ostream
&
os
,
bool
always_show_host
)
const
;
// Print this URI to the ostream.
// PrintWithoutHost only prints components including and after path.
void
PrintWithoutHost
(
std
::
ostream
&
os
)
const
;
void
Print
(
std
::
ostream
&
os
)
const
;
private
:
friend
class
HttpMessage
;
...
...
@@ -179,7 +180,7 @@ inline const std::string& URI::query() const {
}
inline
std
::
ostream
&
operator
<<
(
std
::
ostream
&
os
,
const
URI
&
uri
)
{
uri
.
Print
(
os
,
true
/*always show host*/
);
uri
.
Print
(
os
);
return
os
;
}
...
...
test/brpc_channel_unittest.cpp
View file @
691b8a15
...
...
@@ -2464,4 +2464,61 @@ TEST_F(ChannelTest, unused) {
ASSERT_EQ
(
EINVAL
,
bthread_id_error
(
cid2
,
ECANCELED
));
}
}
TEST_F
(
ChannelTest
,
adaptive_connection_type
)
{
brpc
::
AdaptiveConnectionType
ctype
;
ASSERT_EQ
(
brpc
::
CONNECTION_TYPE_UNKNOWN
,
ctype
);
ASSERT_FALSE
(
ctype
.
has_error
());
ASSERT_STREQ
(
"unknown"
,
ctype
.
name
());
ctype
=
brpc
::
CONNECTION_TYPE_SINGLE
;
ASSERT_EQ
(
brpc
::
CONNECTION_TYPE_SINGLE
,
ctype
);
ASSERT_STREQ
(
"single"
,
ctype
.
name
());
ctype
=
"shorT"
;
ASSERT_EQ
(
brpc
::
CONNECTION_TYPE_SHORT
,
ctype
);
ASSERT_STREQ
(
"short"
,
ctype
.
name
());
ctype
=
"PooLed"
;
ASSERT_EQ
(
brpc
::
CONNECTION_TYPE_POOLED
,
ctype
);
ASSERT_STREQ
(
"pooled"
,
ctype
.
name
());
ctype
=
"SINGLE"
;
ASSERT_EQ
(
brpc
::
CONNECTION_TYPE_SINGLE
,
ctype
);
ASSERT_FALSE
(
ctype
.
has_error
());
ASSERT_STREQ
(
"single"
,
ctype
.
name
());
ctype
=
"blah"
;
ASSERT_EQ
(
brpc
::
CONNECTION_TYPE_UNKNOWN
,
ctype
);
ASSERT_TRUE
(
ctype
.
has_error
());
ASSERT_STREQ
(
"unknown"
,
ctype
.
name
());
ctype
=
"single"
;
ASSERT_EQ
(
brpc
::
CONNECTION_TYPE_SINGLE
,
ctype
);
ASSERT_FALSE
(
ctype
.
has_error
());
ASSERT_STREQ
(
"single"
,
ctype
.
name
());
}
TEST_F
(
ChannelTest
,
adaptive_protocol_type
)
{
brpc
::
AdaptiveProtocolType
ptype
;
ASSERT_EQ
(
brpc
::
PROTOCOL_UNKNOWN
,
ptype
);
ASSERT_STREQ
(
"unknown"
,
ptype
.
name
());
ptype
=
brpc
::
PROTOCOL_HTTP
;
ASSERT_EQ
(
brpc
::
PROTOCOL_HTTP
,
ptype
);
ASSERT_STREQ
(
"http"
,
ptype
.
name
());
ptype
=
"HuLu_pbRPC"
;
ASSERT_EQ
(
brpc
::
PROTOCOL_HULU_PBRPC
,
ptype
);
ASSERT_STREQ
(
"hulu_pbrpc"
,
ptype
.
name
());
ptype
=
"blah"
;
ASSERT_EQ
(
brpc
::
PROTOCOL_UNKNOWN
,
ptype
);
ASSERT_STREQ
(
"unknown"
,
ptype
.
name
());
ptype
=
"Baidu_STD"
;
ASSERT_EQ
(
brpc
::
PROTOCOL_BAIDU_STD
,
ptype
);
ASSERT_STREQ
(
"baidu_std"
,
ptype
.
name
());
}
}
//namespace
test/brpc_http_message_unittest.cpp
View file @
691b8a15
...
...
@@ -318,8 +318,77 @@ TEST(HttpMessageTest, http_header) {
header
.
reason_phrase
());
}
TEST
(
HttpMessageTest
,
em
tp
y_url
)
{
TEST
(
HttpMessageTest
,
em
pt
y_url
)
{
base
::
EndPoint
host
;
ASSERT_FALSE
(
ParseHttpServerAddress
(
&
host
,
""
));
}
TEST
(
HttpMessageTest
,
serialize_http_request
)
{
brpc
::
HttpHeader
header
;
ASSERT_EQ
(
0u
,
header
.
HeaderCount
());
header
.
SetHeader
(
"Foo"
,
"Bar"
);
ASSERT_EQ
(
1u
,
header
.
HeaderCount
());
header
.
set_method
(
brpc
::
HTTP_METHOD_POST
);
base
::
EndPoint
ep
;
ASSERT_EQ
(
0
,
base
::
str2endpoint
(
"127.0.0.1:1234"
,
&
ep
));
base
::
IOBuf
request
;
base
::
IOBuf
content
;
content
.
append
(
"data"
);
SerializeHttpRequest
(
&
request
,
&
header
,
ep
,
&
content
);
ASSERT_EQ
(
"POST / HTTP/1.1
\r\n
Content-Length:4
\r\n
Host:127.0.0.1:1234
\r\n
Foo:Bar
\r\n
Accept:*/*
\r\n
User-Agent:baidu-rpc/1.0 curl/7.0
\r\n\r\n
data"
,
request
);
// user-set content-length is ignored.
header
.
SetHeader
(
"Content-Length"
,
"100"
);
SerializeHttpRequest
(
&
request
,
&
header
,
ep
,
&
content
);
ASSERT_EQ
(
"POST / HTTP/1.1
\r\n
Content-Length:4
\r\n
Host:127.0.0.1:1234
\r\n
Foo:Bar
\r\n
Accept:*/*
\r\n
User-Agent:baidu-rpc/1.0 curl/7.0
\r\n\r\n
data"
,
request
);
// user-host overwrites passed-in remote_side
header
.
SetHeader
(
"Host"
,
"MyHost:4321"
);
SerializeHttpRequest
(
&
request
,
&
header
,
ep
,
&
content
);
ASSERT_EQ
(
"POST / HTTP/1.1
\r\n
Content-Length:4
\r\n
Foo:Bar
\r\n
Host:MyHost:4321
\r\n
Accept:*/*
\r\n
User-Agent:baidu-rpc/1.0 curl/7.0
\r\n\r\n
data"
,
request
);
// user-set accept
header
.
SetHeader
(
"accePT"
/*intended uppercase*/
,
"blahblah"
);
SerializeHttpRequest
(
&
request
,
&
header
,
ep
,
&
content
);
ASSERT_EQ
(
"POST / HTTP/1.1
\r\n
Content-Length:4
\r\n
accePT:blahblah
\r\n
Foo:Bar
\r\n
Host:MyHost:4321
\r\n
User-Agent:baidu-rpc/1.0 curl/7.0
\r\n\r\n
data"
,
request
);
// user-set UA
header
.
SetHeader
(
"user-AGENT"
,
"myUA"
);
SerializeHttpRequest
(
&
request
,
&
header
,
ep
,
&
content
);
ASSERT_EQ
(
"POST / HTTP/1.1
\r\n
Content-Length:4
\r\n
accePT:blahblah
\r\n
user-AGENT:myUA
\r\n
Foo:Bar
\r\n
Host:MyHost:4321
\r\n\r\n
data"
,
request
);
// user-set Authorization
header
.
SetHeader
(
"authorization"
,
"myAuthString"
);
SerializeHttpRequest
(
&
request
,
&
header
,
ep
,
&
content
);
ASSERT_EQ
(
"POST / HTTP/1.1
\r\n
Content-Length:4
\r\n
accePT:blahblah
\r\n
user-AGENT:myUA
\r\n
authorization:myAuthString
\r\n
Foo:Bar
\r\n
Host:MyHost:4321
\r\n\r\n
data"
,
request
);
// GET does not serialize content
header
.
set_method
(
brpc
::
HTTP_METHOD_GET
);
SerializeHttpRequest
(
&
request
,
&
header
,
ep
,
&
content
);
ASSERT_EQ
(
"GET / HTTP/1.1
\r\n
accePT:blahblah
\r\n
user-AGENT:myUA
\r\n
authorization:myAuthString
\r\n
Foo:Bar
\r\n
Host:MyHost:4321
\r\n\r\n
"
,
request
);
}
TEST
(
HttpMessageTest
,
serialize_http_response
)
{
brpc
::
HttpHeader
header
;
header
.
SetHeader
(
"Foo"
,
"Bar"
);
header
.
set_method
(
brpc
::
HTTP_METHOD_POST
);
base
::
IOBuf
response
;
base
::
IOBuf
content
;
content
.
append
(
"data"
);
SerializeHttpResponse
(
&
response
,
&
header
,
&
content
);
ASSERT_EQ
(
"HTTP/1.1 200 OK
\r\n
Content-Length:4
\r\n
Foo:Bar
\r\n\r\n
data"
,
response
);
// content is cleared.
CHECK
(
content
.
empty
());
// user-set content-length is ignored.
content
.
append
(
"data2"
);
header
.
SetHeader
(
"Content-Length"
,
"100"
);
SerializeHttpResponse
(
&
response
,
&
header
,
&
content
);
ASSERT_EQ
(
"HTTP/1.1 200 OK
\r\n
Content-Length:5
\r\n
Foo:Bar
\r\n\r\n
data2"
,
response
);
// null content
SerializeHttpResponse
(
&
response
,
&
header
,
NULL
);
ASSERT_EQ
(
"HTTP/1.1 200 OK
\r\n
Foo:Bar
\r\n\r\n
"
,
response
);
}
}
//namespace
test/brpc_uri_unittest.cpp
View file @
691b8a15
...
...
@@ -295,29 +295,29 @@ TEST(URITest, print_url) {
const
std
::
string
url1
=
"http://user:passwd@a.b.c/?d=c&a=b&e=f#frg1"
;
ASSERT_EQ
(
0
,
uri
.
SetHttpURL
(
url1
));
std
::
ostringstream
oss
;
uri
.
Print
(
oss
,
true
);
uri
.
Print
(
oss
);
ASSERT_EQ
(
"http://a.b.c/?d=c&a=b&e=f#frg1"
,
oss
.
str
());
oss
.
str
(
""
);
uri
.
Print
(
oss
,
false
);
uri
.
Print
WithoutHost
(
oss
);
ASSERT_EQ
(
"/?d=c&a=b&e=f#frg1"
,
oss
.
str
());
const
std
::
string
url2
=
"http://a.b.c/?d=c&a=b&e=f#frg1"
;
ASSERT_EQ
(
0
,
uri
.
SetHttpURL
(
url2
));
oss
.
str
(
""
);
uri
.
Print
(
oss
,
true
);
uri
.
Print
(
oss
);
ASSERT_EQ
(
url2
,
oss
.
str
());
oss
.
str
(
""
);
uri
.
Print
(
oss
,
false
);
uri
.
Print
WithoutHost
(
oss
);
ASSERT_EQ
(
"/?d=c&a=b&e=f#frg1"
,
oss
.
str
());
uri
.
SetQuery
(
"e"
,
"f2"
);
uri
.
SetQuery
(
"f"
,
"g"
);
ASSERT_EQ
((
size_t
)
1
,
uri
.
RemoveQuery
(
"a"
));
oss
.
str
(
""
);
uri
.
Print
(
oss
,
true
);
uri
.
Print
(
oss
);
ASSERT_EQ
(
"http://a.b.c/?d=c&e=f2&f=g#frg1"
,
oss
.
str
());
oss
.
str
(
""
);
uri
.
Print
(
oss
,
false
);
uri
.
Print
WithoutHost
(
oss
);
ASSERT_EQ
(
"/?d=c&e=f2&f=g#frg1"
,
oss
.
str
());
}
...
...
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