3 * Copyright 2004--2011, Google Inc.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 #include "talk/base/asynchttprequest.h"
30 #include "talk/base/gunit.h"
31 #include "talk/base/httpserver.h"
32 #include "talk/base/socketstream.h"
33 #include "talk/base/thread.h"
37 static const SocketAddress kServerAddr("127.0.0.1", 0);
38 static const SocketAddress kServerHostnameAddr("localhost", 0);
39 static const char kServerGetPath[] = "/get";
40 static const char kServerPostPath[] = "/post";
41 static const char kServerResponse[] = "This is a test";
43 class TestHttpServer : public HttpServer, public sigslot::has_slots<> {
45 TestHttpServer(Thread* thread, const SocketAddress& addr) :
46 socket_(thread->socketserver()->CreateAsyncSocket(addr.family(),
50 socket_->SignalReadEvent.connect(this, &TestHttpServer::OnAccept);
53 SocketAddress address() const { return socket_->GetLocalAddress(); }
54 void Close() const { socket_->Close(); }
57 void OnAccept(AsyncSocket* socket) {
58 AsyncSocket* new_socket = socket_->Accept(NULL);
60 HandleConnection(new SocketStream(new_socket));
63 talk_base::scoped_ptr<AsyncSocket> socket_;
66 class AsyncHttpRequestTest : public testing::Test,
67 public sigslot::has_slots<> {
69 AsyncHttpRequestTest()
72 server_(Thread::Current(), kServerAddr) {
73 server_.SignalHttpRequest.connect(this, &AsyncHttpRequestTest::OnRequest);
76 bool started() const { return started_; }
77 bool done() const { return done_; }
79 AsyncHttpRequest* CreateGetRequest(const std::string& host, int port,
80 const std::string& path) {
81 talk_base::AsyncHttpRequest* request =
82 new talk_base::AsyncHttpRequest("unittest");
83 request->SignalWorkDone.connect(this,
84 &AsyncHttpRequestTest::OnRequestDone);
85 request->request().verb = talk_base::HV_GET;
86 request->set_host(host);
87 request->set_port(port);
88 request->request().path = path;
89 request->response().document.reset(new MemoryStream());
92 AsyncHttpRequest* CreatePostRequest(const std::string& host, int port,
93 const std::string& path,
94 const std::string content_type,
95 StreamInterface* content) {
96 talk_base::AsyncHttpRequest* request =
97 new talk_base::AsyncHttpRequest("unittest");
98 request->SignalWorkDone.connect(this,
99 &AsyncHttpRequestTest::OnRequestDone);
100 request->request().verb = talk_base::HV_POST;
101 request->set_host(host);
102 request->set_port(port);
103 request->request().path = path;
104 request->request().setContent(content_type, content);
105 request->response().document.reset(new MemoryStream());
109 const TestHttpServer& server() const { return server_; }
112 void OnRequest(HttpServer* server, HttpServerTransaction* t) {
115 if (t->request.path == kServerGetPath) {
116 t->response.set_success("text/plain", new MemoryStream(kServerResponse));
117 } else if (t->request.path == kServerPostPath) {
118 // reverse the data and reply
120 StreamInterface* in = t->request.document.get();
121 StreamInterface* out = new MemoryStream();
123 for (size_t i = 0; i < size; ++i) {
125 in->SetPosition(size - i - 1);
126 in->Read(&ch, 1, NULL, NULL);
127 out->Write(&ch, 1, NULL, NULL);
130 t->response.set_success("text/plain", out);
132 t->response.set_error(404);
136 void OnRequestDone(SignalThread* thread) {
143 TestHttpServer server_;
146 TEST_F(AsyncHttpRequestTest, TestGetSuccess) {
147 AsyncHttpRequest* req = CreateGetRequest(
148 kServerHostnameAddr.hostname(), server().address().port(),
150 EXPECT_FALSE(started());
152 EXPECT_TRUE_WAIT(started(), 5000); // Should have started by now.
153 EXPECT_TRUE_WAIT(done(), 5000);
154 std::string response;
155 EXPECT_EQ(200U, req->response().scode);
156 ASSERT_TRUE(req->response().document);
157 req->response().document->Rewind();
158 req->response().document->ReadLine(&response);
159 EXPECT_EQ(kServerResponse, response);
163 TEST_F(AsyncHttpRequestTest, TestGetNotFound) {
164 AsyncHttpRequest* req = CreateGetRequest(
165 kServerHostnameAddr.hostname(), server().address().port(),
168 EXPECT_TRUE_WAIT(done(), 5000);
170 EXPECT_EQ(404U, req->response().scode);
171 ASSERT_TRUE(req->response().document);
172 req->response().document->GetSize(&size);
177 TEST_F(AsyncHttpRequestTest, TestGetToNonServer) {
178 AsyncHttpRequest* req = CreateGetRequest(
179 "127.0.0.1", server().address().port(),
181 // Stop the server before we send the request.
184 EXPECT_TRUE_WAIT(done(), 10000);
186 EXPECT_EQ(500U, req->response().scode);
187 ASSERT_TRUE(req->response().document);
188 req->response().document->GetSize(&size);
193 TEST_F(AsyncHttpRequestTest, DISABLED_TestGetToInvalidHostname) {
194 AsyncHttpRequest* req = CreateGetRequest(
195 "invalid", server().address().port(),
198 EXPECT_TRUE_WAIT(done(), 5000);
200 EXPECT_EQ(500U, req->response().scode);
201 ASSERT_TRUE(req->response().document);
202 req->response().document->GetSize(&size);
207 TEST_F(AsyncHttpRequestTest, TestPostSuccess) {
208 AsyncHttpRequest* req = CreatePostRequest(
209 kServerHostnameAddr.hostname(), server().address().port(),
210 kServerPostPath, "text/plain", new MemoryStream("abcd1234"));
212 EXPECT_TRUE_WAIT(done(), 5000);
213 std::string response;
214 EXPECT_EQ(200U, req->response().scode);
215 ASSERT_TRUE(req->response().document);
216 req->response().document->Rewind();
217 req->response().document->ReadLine(&response);
218 EXPECT_EQ("4321dcba", response);
222 // Ensure that we shut down properly even if work is outstanding.
223 TEST_F(AsyncHttpRequestTest, TestCancel) {
224 AsyncHttpRequest* req = CreateGetRequest(
225 kServerHostnameAddr.hostname(), server().address().port(),
231 TEST_F(AsyncHttpRequestTest, TestGetSuccessDelay) {
232 AsyncHttpRequest* req = CreateGetRequest(
233 kServerHostnameAddr.hostname(), server().address().port(),
235 req->set_start_delay(10); // Delay 10ms.
238 EXPECT_FALSE(started()); // Should not have started immediately.
239 EXPECT_TRUE_WAIT(started(), 5000); // Should have started by now.
240 EXPECT_TRUE_WAIT(done(), 5000);
241 std::string response;
242 EXPECT_EQ(200U, req->response().scode);
243 ASSERT_TRUE(req->response().document);
244 req->response().document->Rewind();
245 req->response().document->ReadLine(&response);
246 EXPECT_EQ(kServerResponse, response);
250 } // namespace talk_base