Commit 691b8a15 authored by gejun's avatar gejun

patch svn r34971

Change-Id: I2dab12ac61990359fc34d04c42aeb23aa92960eb
parent 456243ee
......@@ -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 (header.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 (!header.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 = header.HeaderBegin();
it != header.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 (header.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 (header.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 = header.uri().user_info();
if (!user_info.empty() && header.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 (header.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/" << header.major_version() << '.'
<< header.minor_version() << ' ' << header.status_code()
<< ' ' << header.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 (!header.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 = header.HeaderBegin();
it != header.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);
......
......@@ -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
......
......@@ -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);
......
......@@ -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
......
......@@ -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;
}
......
......@@ -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
......@@ -318,8 +318,77 @@ TEST(HttpMessageTest, http_header) {
header.reason_phrase());
}
TEST(HttpMessageTest, emtpy_url) {
TEST(HttpMessageTest, empty_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\nContent-Length:4\r\nHost:127.0.0.1:1234\r\nFoo:Bar\r\nAccept:*/*\r\nUser-Agent:baidu-rpc/1.0 curl/7.0\r\n\r\ndata", request);
// user-set content-length is ignored.
header.SetHeader("Content-Length", "100");
SerializeHttpRequest(&request, &header, ep, &content);
ASSERT_EQ("POST / HTTP/1.1\r\nContent-Length:4\r\nHost:127.0.0.1:1234\r\nFoo:Bar\r\nAccept:*/*\r\nUser-Agent:baidu-rpc/1.0 curl/7.0\r\n\r\ndata", 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\nContent-Length:4\r\nFoo:Bar\r\nHost:MyHost:4321\r\nAccept:*/*\r\nUser-Agent:baidu-rpc/1.0 curl/7.0\r\n\r\ndata", request);
// user-set accept
header.SetHeader("accePT"/*intended uppercase*/, "blahblah");
SerializeHttpRequest(&request, &header, ep, &content);
ASSERT_EQ("POST / HTTP/1.1\r\nContent-Length:4\r\naccePT:blahblah\r\nFoo:Bar\r\nHost:MyHost:4321\r\nUser-Agent:baidu-rpc/1.0 curl/7.0\r\n\r\ndata", request);
// user-set UA
header.SetHeader("user-AGENT", "myUA");
SerializeHttpRequest(&request, &header, ep, &content);
ASSERT_EQ("POST / HTTP/1.1\r\nContent-Length:4\r\naccePT:blahblah\r\nuser-AGENT:myUA\r\nFoo:Bar\r\nHost:MyHost:4321\r\n\r\ndata", request);
// user-set Authorization
header.SetHeader("authorization", "myAuthString");
SerializeHttpRequest(&request, &header, ep, &content);
ASSERT_EQ("POST / HTTP/1.1\r\nContent-Length:4\r\naccePT:blahblah\r\nuser-AGENT:myUA\r\nauthorization:myAuthString\r\nFoo:Bar\r\nHost:MyHost:4321\r\n\r\ndata", 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\naccePT:blahblah\r\nuser-AGENT:myUA\r\nauthorization:myAuthString\r\nFoo:Bar\r\nHost: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\nContent-Length:4\r\nFoo:Bar\r\n\r\ndata", 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\nContent-Length:5\r\nFoo:Bar\r\n\r\ndata2", response);
// null content
SerializeHttpResponse(&response, &header, NULL);
ASSERT_EQ("HTTP/1.1 200 OK\r\nFoo:Bar\r\n\r\n", response);
}
} //namespace
......@@ -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.PrintWithoutHost(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.PrintWithoutHost(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.PrintWithoutHost(oss);
ASSERT_EQ("/?d=c&e=f2&f=g#frg1", oss.str());
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment