123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407 |
- // Licensed to the Apache Software Foundation (ASF) under one
- // or more contributor license agreements. See the NOTICE file
- // distributed with this work for additional information
- // regarding copyright ownership. The ASF licenses this file
- // to you under the Apache License, Version 2.0 (the
- // "License"); you may not use this file except in compliance
- // with the License. You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing,
- // software distributed under the License is distributed on an
- // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- // KIND, either express or implied. See the License for the
- // specific language governing permissions and limitations
- // under the License.
- //
- // Date 2014/10/24 16:44:30
- #include <gtest/gtest.h>
- #include <google/protobuf/descriptor.h>
- #include "brpc/server.h"
- #include "brpc/details/http_message.h"
- #include "brpc/policy/http_rpc_protocol.h"
- #include "echo.pb.h"
- namespace brpc {
- namespace policy {
- Server::MethodProperty*
- FindMethodPropertyByURI(const std::string& uri_path, const Server* server,
- std::string* unknown_method_str);
- bool ParseHttpServerAddress(butil::EndPoint *point, const char *server_addr_and_port);
- }}
- namespace {
- using brpc::policy::FindMethodPropertyByURI;
- using brpc::policy::ParseHttpServerAddress;
- TEST(HttpMessageTest, http_method) {
- ASSERT_STREQ("DELETE", brpc::HttpMethod2Str(brpc::HTTP_METHOD_DELETE));
- ASSERT_STREQ("GET", brpc::HttpMethod2Str(brpc::HTTP_METHOD_GET));
- ASSERT_STREQ("POST", brpc::HttpMethod2Str(brpc::HTTP_METHOD_POST));
- ASSERT_STREQ("PUT", brpc::HttpMethod2Str(brpc::HTTP_METHOD_PUT));
- brpc::HttpMethod m;
- ASSERT_TRUE(brpc::Str2HttpMethod("DELETE", &m));
- ASSERT_EQ(brpc::HTTP_METHOD_DELETE, m);
- ASSERT_TRUE(brpc::Str2HttpMethod("GET", &m));
- ASSERT_EQ(brpc::HTTP_METHOD_GET, m);
- ASSERT_TRUE(brpc::Str2HttpMethod("POST", &m));
- ASSERT_EQ(brpc::HTTP_METHOD_POST, m);
- ASSERT_TRUE(brpc::Str2HttpMethod("PUT", &m));
- ASSERT_EQ(brpc::HTTP_METHOD_PUT, m);
- // case-insensitive
- ASSERT_TRUE(brpc::Str2HttpMethod("DeLeTe", &m));
- ASSERT_EQ(brpc::HTTP_METHOD_DELETE, m);
- ASSERT_TRUE(brpc::Str2HttpMethod("get", &m));
- ASSERT_EQ(brpc::HTTP_METHOD_GET, m);
- // non-existed
- ASSERT_FALSE(brpc::Str2HttpMethod("DEL", &m));
- ASSERT_FALSE(brpc::Str2HttpMethod("DELETE ", &m));
- ASSERT_FALSE(brpc::Str2HttpMethod("GOT", &m));
- }
- TEST(HttpMessageTest, eof) {
- GFLAGS_NS::SetCommandLineOption("verbose", "100");
- const char* http_request =
- "GET /CloudApiControl/HttpServer/telematics/v3/weather?location=%E6%B5%B7%E5%8D%97%E7%9C%81%E7%9B%B4%E8%BE%96%E5%8E%BF%E7%BA%A7%E8%A1%8C%E6%94%BF%E5%8D%95%E4%BD%8D&output=json&ak=0l3FSP6qA0WbOzGRaafbmczS HTTP/1.1\r\n"
- "X-Host: api.map.baidu.com\r\n"
- "X-Forwarded-Proto: http\r\n"
- "Host: api.map.baidu.com\r\n"
- "User-Agent: IME/Android/4.4.2/N80.QHD.LT.X10.V3/N80.QHD.LT.X10.V3.20150812.031915\r\n"
- "Accept: application/json\r\n"
- "Accept-Charset: UTF-8,*;q=0.5\r\n"
- "Accept-Encoding: deflate,sdch\r\n"
- "Accept-Language: zh-CN,en-US;q=0.8,zh;q=0.6\r\n"
- "Bfe-Atk: NORMAL_BROWSER\r\n"
- "Bfe_logid: 8767802212038413243\r\n"
- "Bfeip: 10.26.124.40\r\n"
- "CLIENTIP: 119.29.102.26\r\n"
- "CLIENTPORT: 59863\r\n"
- "Cache-Control: max-age=0\r\n"
- "Content-Type: application/json;charset=utf8\r\n"
- "X-Forwarded-For: 119.29.102.26\r\n"
- "X-Forwarded-Port: 59863\r\n"
- "X-Ime-Imei: 35629601890905\r\n"
- "X_BD_LOGID: 3959476981\r\n"
- "X_BD_LOGID64: 16815814797661447369\r\n"
- "X_BD_PRODUCT: map\r\n"
- "X_BD_SUBSYS: apimap\r\n";
- butil::IOBuf buf;
- buf.append(http_request);
- brpc::HttpMessage http_message;
- ASSERT_EQ((ssize_t)buf.size(), http_message.ParseFromIOBuf(buf));
- ASSERT_EQ(2, http_message.ParseFromArray("\r\n", 2));
- ASSERT_TRUE(http_message.Completed());
- }
- TEST(HttpMessageTest, request_sanity) {
- const char *http_request =
- "POST /path/file.html?sdfsdf=sdfs&sldf1=sdf HTTP/12.34\r\n"
- "From: someuser@jmarshall.com\r\n"
- "User-Agent: HTTPTool/1.0 \r\n" // intended ending spaces
- "Content-Type: json\r\n"
- "Content-Length: 19\r\n"
- "Log-ID: 456\r\n"
- "Host: myhost\r\n"
- "Correlation-ID: 123\r\n"
- "Authorization: test\r\n"
- "Accept: */*\r\n"
- "\r\n"
- "Message Body sdfsdf\r\n"
- ;
- brpc::HttpMessage http_message;
- ASSERT_EQ((ssize_t)strlen(http_request),
- http_message.ParseFromArray(http_request, strlen(http_request)));
- const brpc::HttpHeader& header = http_message.header();
- // Check all keys
- ASSERT_EQ("json", header.content_type());
- ASSERT_TRUE(header.GetHeader("HOST"));
- ASSERT_EQ("myhost", *header.GetHeader("host"));
- ASSERT_TRUE(header.GetHeader("CORRELATION-ID"));
- ASSERT_EQ("123", *header.GetHeader("CORRELATION-ID"));
- ASSERT_TRUE(header.GetHeader("User-Agent"));
- ASSERT_EQ("HTTPTool/1.0 ", *header.GetHeader("User-Agent"));
- ASSERT_TRUE(header.GetHeader("Host"));
- ASSERT_EQ("myhost", *header.GetHeader("Host"));
- ASSERT_TRUE(header.GetHeader("Accept"));
- ASSERT_EQ("*/*", *header.GetHeader("Accept"));
-
- ASSERT_EQ(1, header.major_version());
- ASSERT_EQ(34, header.minor_version());
- ASSERT_EQ(brpc::HTTP_METHOD_POST, header.method());
- ASSERT_EQ(brpc::HTTP_STATUS_OK, header.status_code());
- ASSERT_STREQ("OK", header.reason_phrase());
- ASSERT_TRUE(header.GetHeader("log-id"));
- ASSERT_EQ("456", *header.GetHeader("log-id"));
- ASSERT_TRUE(NULL != header.GetHeader("Authorization"));
- ASSERT_EQ("test", *header.GetHeader("Authorization"));
- }
- TEST(HttpMessageTest, response_sanity) {
- const char *http_response =
- "HTTP/12.34 410 GoneBlah\r\n"
- "From: someuser@jmarshall.com\r\n"
- "User-Agent: HTTPTool/1.0 \r\n" // intended ending spaces
- "Content-Type: json2\r\n"
- "Content-Length: 19\r\n"
- "Log-ID: 456\r\n"
- "Host: myhost\r\n"
- "Correlation-ID: 123\r\n"
- "Authorization: test\r\n"
- "Accept: */*\r\n"
- "\r\n"
- "Message Body sdfsdf\r\n"
- ;
- brpc::HttpMessage http_message;
- ASSERT_EQ((ssize_t)strlen(http_response),
- http_message.ParseFromArray(http_response, strlen(http_response)));
- // Check all keys
- const brpc::HttpHeader& header = http_message.header();
- ASSERT_EQ("json2", header.content_type());
- ASSERT_TRUE(header.GetHeader("HOST"));
- ASSERT_EQ("myhost", *header.GetHeader("host"));
- ASSERT_TRUE(header.GetHeader("CORRELATION-ID"));
- ASSERT_EQ("123", *header.GetHeader("CORRELATION-ID"));
- ASSERT_TRUE(header.GetHeader("User-Agent"));
- ASSERT_EQ("HTTPTool/1.0 ", *header.GetHeader("User-Agent"));
- ASSERT_TRUE(header.GetHeader("Host"));
- ASSERT_EQ("myhost", *header.GetHeader("Host"));
- ASSERT_TRUE(header.GetHeader("Accept"));
- ASSERT_EQ("*/*", *header.GetHeader("Accept"));
-
- ASSERT_EQ(1, header.major_version());
- ASSERT_EQ(34, header.minor_version());
- // method is undefined for response, in our case, it's set to 0.
- ASSERT_EQ(brpc::HTTP_METHOD_DELETE, header.method());
- ASSERT_EQ(brpc::HTTP_STATUS_GONE, header.status_code());
- ASSERT_STREQ(brpc::HttpReasonPhrase(header.status_code()), /*not GoneBlah*/
- header.reason_phrase());
-
- ASSERT_TRUE(header.GetHeader("log-id"));
- ASSERT_EQ("456", *header.GetHeader("log-id"));
- ASSERT_TRUE(header.GetHeader("Authorization"));
- ASSERT_EQ("test", *header.GetHeader("Authorization"));
- }
- TEST(HttpMessageTest, bad_format) {
- const char *http_request =
- "slkdjflksdf skldjf\r\n";
- brpc::HttpMessage http_message;
- ASSERT_EQ(-1, http_message.ParseFromArray(http_request, strlen(http_request)));
- }
- TEST(HttpMessageTest, incompleted_request_line) {
- const char *http_request = "GE" ;
- brpc::HttpMessage http_message;
- ASSERT_TRUE(http_message.ParseFromArray(http_request, strlen(http_request)) >= 0);
- ASSERT_FALSE(http_message.Completed());
- }
- TEST(HttpMessageTest, parse_from_iobuf) {
- const size_t content_length = 8192;
- char header[1024];
- snprintf(header, sizeof(header),
- "GET /service/method?key1=value1&key2=value2&key3=value3 HTTP/1.1\r\n"
- "Content-Type: text/plain\r\n"
- "Content-Length: %lu\r\n"
- "\r\n",
- content_length);
- std::string content;
- for (size_t i = 0; i < content_length; ++i) content.push_back('2');
- butil::IOBuf request;
- request.append(header);
- request.append(content);
- brpc::HttpMessage http_message;
- ASSERT_TRUE(http_message.ParseFromIOBuf(request) >= 0);
- ASSERT_TRUE(http_message.Completed());
- ASSERT_EQ(content, http_message.body().to_string());
- ASSERT_EQ("text/plain", http_message.header().content_type());
- }
- TEST(HttpMessageTest, find_method_property_by_uri) {
- brpc::Server server;
- ASSERT_EQ(0, server.AddService(new test::EchoService(),
- brpc::SERVER_OWNS_SERVICE));
- ASSERT_EQ(0, server.Start(9237, NULL));
- std::string unknown_method;
- brpc::Server::MethodProperty* mp = NULL;
-
- mp = FindMethodPropertyByURI("", &server, NULL);
- ASSERT_TRUE(mp);
- ASSERT_EQ("index", mp->method->service()->name());
- mp = FindMethodPropertyByURI("/", &server, NULL);
- ASSERT_TRUE(mp);
- ASSERT_EQ("index", mp->method->service()->name());
- mp = FindMethodPropertyByURI("//", &server, NULL);
- ASSERT_TRUE(mp);
- ASSERT_EQ("index", mp->method->service()->name());
- mp = FindMethodPropertyByURI("flags", &server, &unknown_method);
- ASSERT_TRUE(mp);
- ASSERT_EQ("flags", mp->method->service()->name());
-
- mp = FindMethodPropertyByURI("/flags/port", &server, &unknown_method);
- ASSERT_TRUE(mp);
- ASSERT_EQ("flags", mp->method->service()->name());
- ASSERT_EQ("port", unknown_method);
-
- mp = FindMethodPropertyByURI("/flags/foo/bar", &server, &unknown_method);
- ASSERT_TRUE(mp);
- ASSERT_EQ("flags", mp->method->service()->name());
- ASSERT_EQ("foo/bar", unknown_method);
-
- mp = FindMethodPropertyByURI("/brpc.flags/$*",
- &server, &unknown_method);
- ASSERT_TRUE(mp);
- ASSERT_EQ("flags", mp->method->service()->name());
- ASSERT_EQ("$*", unknown_method);
- mp = FindMethodPropertyByURI("EchoService/Echo", &server, &unknown_method);
- ASSERT_TRUE(mp);
- ASSERT_EQ("test.EchoService.Echo", mp->method->full_name());
-
- mp = FindMethodPropertyByURI("/EchoService/Echo",
- &server, &unknown_method);
- ASSERT_TRUE(mp);
- ASSERT_EQ("test.EchoService.Echo", mp->method->full_name());
-
- mp = FindMethodPropertyByURI("/test.EchoService/Echo",
- &server, &unknown_method);
- ASSERT_TRUE(mp);
- ASSERT_EQ("test.EchoService.Echo", mp->method->full_name());
-
- mp = FindMethodPropertyByURI("/test.EchoService/no_such_method",
- &server, &unknown_method);
- ASSERT_FALSE(mp);
- }
- TEST(HttpMessageTest, http_header) {
- brpc::HttpHeader header;
-
- header.set_version(10, 100);
- ASSERT_EQ(10, header.major_version());
- ASSERT_EQ(100, header.minor_version());
- ASSERT_TRUE(header.content_type().empty());
- header.set_content_type("text/plain");
- ASSERT_EQ("text/plain", header.content_type());
- ASSERT_FALSE(header.GetHeader("content-type"));
- header.set_content_type("application/json");
- ASSERT_EQ("application/json", header.content_type());
- ASSERT_FALSE(header.GetHeader("content-type"));
-
- ASSERT_FALSE(header.GetHeader("key1"));
- header.AppendHeader("key1", "value1");
- const std::string* value = header.GetHeader("key1");
- ASSERT_TRUE(value && *value == "value1");
- header.AppendHeader("key1", "value2");
- value = header.GetHeader("key1");
- ASSERT_TRUE(value && *value == "value1,value2");
- header.SetHeader("key1", "value3");
- value = header.GetHeader("key1");
- ASSERT_TRUE(value && *value == "value3");
- header.RemoveHeader("key1");
- ASSERT_FALSE(header.GetHeader("key1"));
- ASSERT_EQ(brpc::HTTP_METHOD_GET, header.method());
- header.set_method(brpc::HTTP_METHOD_POST);
- ASSERT_EQ(brpc::HTTP_METHOD_POST, header.method());
- ASSERT_EQ(brpc::HTTP_STATUS_OK, header.status_code());
- ASSERT_STREQ(brpc::HttpReasonPhrase(header.status_code()),
- header.reason_phrase());
- header.set_status_code(brpc::HTTP_STATUS_CONTINUE);
- ASSERT_EQ(brpc::HTTP_STATUS_CONTINUE, header.status_code());
- ASSERT_STREQ(brpc::HttpReasonPhrase(header.status_code()),
- header.reason_phrase());
-
- header.set_status_code(brpc::HTTP_STATUS_GONE);
- ASSERT_EQ(brpc::HTTP_STATUS_GONE, header.status_code());
- ASSERT_STREQ(brpc::HttpReasonPhrase(header.status_code()),
- header.reason_phrase());
- }
- TEST(HttpMessageTest, empty_url) {
- butil::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);
- butil::EndPoint ep;
- ASSERT_EQ(0, butil::str2endpoint("127.0.0.1:1234", &ep));
- butil::IOBuf request;
- butil::IOBuf content;
- content.append("data");
- MakeRawHttpRequest(&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: brpc/1.0 curl/7.0\r\n\r\ndata", request);
- // user-set content-length is ignored.
- header.SetHeader("Content-Length", "100");
- MakeRawHttpRequest(&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: brpc/1.0 curl/7.0\r\n\r\ndata", request);
- // user-host overwrites passed-in remote_side
- header.SetHeader("Host", "MyHost: 4321");
- MakeRawHttpRequest(&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: brpc/1.0 curl/7.0\r\n\r\ndata", request);
- // user-set accept
- header.SetHeader("accePT"/*intended uppercase*/, "blahblah");
- MakeRawHttpRequest(&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: brpc/1.0 curl/7.0\r\n\r\ndata", request);
- // user-set UA
- header.SetHeader("user-AGENT", "myUA");
- MakeRawHttpRequest(&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");
- MakeRawHttpRequest(&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);
- MakeRawHttpRequest(&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);
- butil::IOBuf response;
- butil::IOBuf content;
- content.append("data");
- MakeRawHttpResponse(&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");
- MakeRawHttpResponse(&response, &header, &content);
- ASSERT_EQ("HTTP/1.1 200 OK\r\nContent-Length: 5\r\nFoo: Bar\r\n\r\ndata2", response);
- // null content
- MakeRawHttpResponse(&response, &header, NULL);
- ASSERT_EQ("HTTP/1.1 200 OK\r\nFoo: Bar\r\n\r\n", response);
- }
- } //namespace
|