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