Home | History | Annotate | Download | only in base
      1 /*
      2  *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
      3  *
      4  *  Use of this source code is governed by a BSD-style license
      5  *  that can be found in the LICENSE file in the root of the source
      6  *  tree. An additional intellectual property rights grant can be found
      7  *  in the file PATENTS.  All contributing project authors may
      8  *  be found in the AUTHORS file in the root of the source tree.
      9  */
     10 
     11 #include <string>
     12 #include "webrtc/base/asynchttprequest.h"
     13 #include "webrtc/base/gunit.h"
     14 #include "webrtc/base/httpserver.h"
     15 #include "webrtc/base/socketstream.h"
     16 #include "webrtc/base/thread.h"
     17 
     18 namespace rtc {
     19 
     20 static const SocketAddress kServerAddr("127.0.0.1", 0);
     21 static const SocketAddress kServerHostnameAddr("localhost", 0);
     22 static const char kServerGetPath[] = "/get";
     23 static const char kServerPostPath[] = "/post";
     24 static const char kServerResponse[] = "This is a test";
     25 
     26 class TestHttpServer : public HttpServer, public sigslot::has_slots<> {
     27  public:
     28   TestHttpServer(Thread* thread, const SocketAddress& addr) :
     29       socket_(thread->socketserver()->CreateAsyncSocket(addr.family(),
     30                                                         SOCK_STREAM)) {
     31     socket_->Bind(addr);
     32     socket_->Listen(5);
     33     socket_->SignalReadEvent.connect(this, &TestHttpServer::OnAccept);
     34   }
     35 
     36   SocketAddress address() const { return socket_->GetLocalAddress(); }
     37   void Close() const { socket_->Close(); }
     38 
     39  private:
     40   void OnAccept(AsyncSocket* socket) {
     41     AsyncSocket* new_socket = socket_->Accept(NULL);
     42     if (new_socket) {
     43       HandleConnection(new SocketStream(new_socket));
     44     }
     45   }
     46   rtc::scoped_ptr<AsyncSocket> socket_;
     47 };
     48 
     49 class AsyncHttpRequestTest : public testing::Test,
     50                              public sigslot::has_slots<> {
     51  public:
     52   AsyncHttpRequestTest()
     53       : started_(false),
     54         done_(false),
     55         server_(Thread::Current(), kServerAddr) {
     56     server_.SignalHttpRequest.connect(this, &AsyncHttpRequestTest::OnRequest);
     57   }
     58 
     59   bool started() const { return started_; }
     60   bool done() const { return done_; }
     61 
     62   AsyncHttpRequest* CreateGetRequest(const std::string& host, int port,
     63                                      const std::string& path) {
     64     rtc::AsyncHttpRequest* request =
     65         new rtc::AsyncHttpRequest("unittest");
     66     request->SignalWorkDone.connect(this,
     67         &AsyncHttpRequestTest::OnRequestDone);
     68     request->request().verb = rtc::HV_GET;
     69     request->set_host(host);
     70     request->set_port(port);
     71     request->request().path = path;
     72     request->response().document.reset(new MemoryStream());
     73     return request;
     74   }
     75   AsyncHttpRequest* CreatePostRequest(const std::string& host, int port,
     76                                       const std::string& path,
     77                                       const std::string content_type,
     78                                       StreamInterface* content) {
     79     rtc::AsyncHttpRequest* request =
     80         new rtc::AsyncHttpRequest("unittest");
     81     request->SignalWorkDone.connect(this,
     82         &AsyncHttpRequestTest::OnRequestDone);
     83     request->request().verb = rtc::HV_POST;
     84     request->set_host(host);
     85     request->set_port(port);
     86     request->request().path = path;
     87     request->request().setContent(content_type, content);
     88     request->response().document.reset(new MemoryStream());
     89     return request;
     90   }
     91 
     92   const TestHttpServer& server() const { return server_; }
     93 
     94  protected:
     95   void OnRequest(HttpServer* server, HttpServerTransaction* t) {
     96     started_ = true;
     97 
     98     if (t->request.path == kServerGetPath) {
     99       t->response.set_success("text/plain", new MemoryStream(kServerResponse));
    100     } else if (t->request.path == kServerPostPath) {
    101       // reverse the data and reply
    102       size_t size;
    103       StreamInterface* in = t->request.document.get();
    104       StreamInterface* out = new MemoryStream();
    105       in->GetSize(&size);
    106       for (size_t i = 0; i < size; ++i) {
    107         char ch;
    108         in->SetPosition(size - i - 1);
    109         in->Read(&ch, 1, NULL, NULL);
    110         out->Write(&ch, 1, NULL, NULL);
    111       }
    112       out->Rewind();
    113       t->response.set_success("text/plain", out);
    114     } else {
    115       t->response.set_error(404);
    116     }
    117     server_.Respond(t);
    118   }
    119   void OnRequestDone(SignalThread* thread) {
    120     done_ = true;
    121   }
    122 
    123  private:
    124   bool started_;
    125   bool done_;
    126   TestHttpServer server_;
    127 };
    128 
    129 TEST_F(AsyncHttpRequestTest, TestGetSuccess) {
    130   AsyncHttpRequest* req = CreateGetRequest(
    131       kServerHostnameAddr.hostname(), server().address().port(),
    132       kServerGetPath);
    133   EXPECT_FALSE(started());
    134   req->Start();
    135   EXPECT_TRUE_WAIT(started(), 5000);  // Should have started by now.
    136   EXPECT_TRUE_WAIT(done(), 5000);
    137   std::string response;
    138   EXPECT_EQ(200U, req->response().scode);
    139   ASSERT_TRUE(req->response().document);
    140   req->response().document->Rewind();
    141   req->response().document->ReadLine(&response);
    142   EXPECT_EQ(kServerResponse, response);
    143   req->Release();
    144 }
    145 
    146 TEST_F(AsyncHttpRequestTest, TestGetNotFound) {
    147   AsyncHttpRequest* req = CreateGetRequest(
    148       kServerHostnameAddr.hostname(), server().address().port(),
    149       "/bad");
    150   req->Start();
    151   EXPECT_TRUE_WAIT(done(), 5000);
    152   size_t size;
    153   EXPECT_EQ(404U, req->response().scode);
    154   ASSERT_TRUE(req->response().document);
    155   req->response().document->GetSize(&size);
    156   EXPECT_EQ(0U, size);
    157   req->Release();
    158 }
    159 
    160 TEST_F(AsyncHttpRequestTest, TestGetToNonServer) {
    161   AsyncHttpRequest* req = CreateGetRequest(
    162       "127.0.0.1", server().address().port(),
    163       kServerGetPath);
    164   // Stop the server before we send the request.
    165   server().Close();
    166   req->Start();
    167   EXPECT_TRUE_WAIT(done(), 10000);
    168   size_t size;
    169   EXPECT_EQ(500U, req->response().scode);
    170   ASSERT_TRUE(req->response().document);
    171   req->response().document->GetSize(&size);
    172   EXPECT_EQ(0U, size);
    173   req->Release();
    174 }
    175 
    176 TEST_F(AsyncHttpRequestTest, DISABLED_TestGetToInvalidHostname) {
    177   AsyncHttpRequest* req = CreateGetRequest(
    178       "invalid", server().address().port(),
    179       kServerGetPath);
    180   req->Start();
    181   EXPECT_TRUE_WAIT(done(), 5000);
    182   size_t size;
    183   EXPECT_EQ(500U, req->response().scode);
    184   ASSERT_TRUE(req->response().document);
    185   req->response().document->GetSize(&size);
    186   EXPECT_EQ(0U, size);
    187   req->Release();
    188 }
    189 
    190 TEST_F(AsyncHttpRequestTest, TestPostSuccess) {
    191   AsyncHttpRequest* req = CreatePostRequest(
    192       kServerHostnameAddr.hostname(), server().address().port(),
    193       kServerPostPath, "text/plain", new MemoryStream("abcd1234"));
    194   req->Start();
    195   EXPECT_TRUE_WAIT(done(), 5000);
    196   std::string response;
    197   EXPECT_EQ(200U, req->response().scode);
    198   ASSERT_TRUE(req->response().document);
    199   req->response().document->Rewind();
    200   req->response().document->ReadLine(&response);
    201   EXPECT_EQ("4321dcba", response);
    202   req->Release();
    203 }
    204 
    205 // Ensure that we shut down properly even if work is outstanding.
    206 TEST_F(AsyncHttpRequestTest, TestCancel) {
    207   AsyncHttpRequest* req = CreateGetRequest(
    208       kServerHostnameAddr.hostname(), server().address().port(),
    209       kServerGetPath);
    210   req->Start();
    211   req->Destroy(true);
    212 }
    213 
    214 TEST_F(AsyncHttpRequestTest, TestGetSuccessDelay) {
    215   AsyncHttpRequest* req = CreateGetRequest(
    216       kServerHostnameAddr.hostname(), server().address().port(),
    217       kServerGetPath);
    218   req->set_start_delay(10);  // Delay 10ms.
    219   req->Start();
    220   Thread::SleepMs(5);
    221   EXPECT_FALSE(started());  // Should not have started immediately.
    222   EXPECT_TRUE_WAIT(started(), 5000);  // Should have started by now.
    223   EXPECT_TRUE_WAIT(done(), 5000);
    224   std::string response;
    225   EXPECT_EQ(200U, req->response().scode);
    226   ASSERT_TRUE(req->response().document);
    227   req->response().document->Rewind();
    228   req->response().document->ReadLine(&response);
    229   EXPECT_EQ(kServerResponse, response);
    230   req->Release();
    231 }
    232 
    233 }  // namespace rtc
    234