blob: 13842da71b8586ead22037718a746c461d433992 [file] [log] [blame]
henrike@webrtc.org0e118e72013-07-10 00:45:36 +00001/*
2 * libjingle
3 * Copyright 2004--2011, Google Inc.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
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.
15 *
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.
26 */
27
28#include <string>
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"
34
35namespace talk_base {
36
37static const SocketAddress kServerAddr("127.0.0.1", 0);
38static const SocketAddress kServerHostnameAddr("localhost", 0);
39static const char kServerGetPath[] = "/get";
40static const char kServerPostPath[] = "/post";
41static const char kServerResponse[] = "This is a test";
42
43class TestHttpServer : public HttpServer, public sigslot::has_slots<> {
44 public:
45 TestHttpServer(Thread* thread, const SocketAddress& addr) :
46 socket_(thread->socketserver()->CreateAsyncSocket(addr.family(),
47 SOCK_STREAM)) {
48 socket_->Bind(addr);
49 socket_->Listen(5);
50 socket_->SignalReadEvent.connect(this, &TestHttpServer::OnAccept);
51 }
52
53 SocketAddress address() const { return socket_->GetLocalAddress(); }
54 void Close() const { socket_->Close(); }
55
56 private:
57 void OnAccept(AsyncSocket* socket) {
58 AsyncSocket* new_socket = socket_->Accept(NULL);
59 if (new_socket) {
60 HandleConnection(new SocketStream(new_socket));
61 }
62 }
63 talk_base::scoped_ptr<AsyncSocket> socket_;
64};
65
66class AsyncHttpRequestTest : public testing::Test,
67 public sigslot::has_slots<> {
68 public:
69 AsyncHttpRequestTest()
70 : started_(false),
71 done_(false),
72 server_(Thread::Current(), kServerAddr) {
73 server_.SignalHttpRequest.connect(this, &AsyncHttpRequestTest::OnRequest);
74 }
75
76 bool started() const { return started_; }
77 bool done() const { return done_; }
78
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());
90 return request;
91 }
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());
106 return request;
107 }
108
109 const TestHttpServer& server() const { return server_; }
110
111 protected:
112 void OnRequest(HttpServer* server, HttpServerTransaction* t) {
113 started_ = true;
114
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
119 size_t size;
120 StreamInterface* in = t->request.document.get();
121 StreamInterface* out = new MemoryStream();
122 in->GetSize(&size);
123 for (size_t i = 0; i < size; ++i) {
124 char ch;
125 in->SetPosition(size - i - 1);
126 in->Read(&ch, 1, NULL, NULL);
127 out->Write(&ch, 1, NULL, NULL);
128 }
129 out->Rewind();
130 t->response.set_success("text/plain", out);
131 } else {
132 t->response.set_error(404);
133 }
134 server_.Respond(t);
135 }
136 void OnRequestDone(SignalThread* thread) {
137 done_ = true;
138 }
139
140 private:
141 bool started_;
142 bool done_;
143 TestHttpServer server_;
144};
145
146TEST_F(AsyncHttpRequestTest, TestGetSuccess) {
147 AsyncHttpRequest* req = CreateGetRequest(
148 kServerHostnameAddr.hostname(), server().address().port(),
149 kServerGetPath);
150 EXPECT_FALSE(started());
151 req->Start();
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);
160 req->Release();
161}
162
163TEST_F(AsyncHttpRequestTest, TestGetNotFound) {
164 AsyncHttpRequest* req = CreateGetRequest(
165 kServerHostnameAddr.hostname(), server().address().port(),
166 "/bad");
167 req->Start();
168 EXPECT_TRUE_WAIT(done(), 5000);
169 size_t size;
170 EXPECT_EQ(404U, req->response().scode);
171 ASSERT_TRUE(req->response().document);
172 req->response().document->GetSize(&size);
173 EXPECT_EQ(0U, size);
174 req->Release();
175}
176
177TEST_F(AsyncHttpRequestTest, TestGetToNonServer) {
178 AsyncHttpRequest* req = CreateGetRequest(
179 "127.0.0.1", server().address().port(),
180 kServerGetPath);
181 // Stop the server before we send the request.
182 server().Close();
183 req->Start();
184 EXPECT_TRUE_WAIT(done(), 10000);
185 size_t size;
186 EXPECT_EQ(500U, req->response().scode);
187 ASSERT_TRUE(req->response().document);
188 req->response().document->GetSize(&size);
189 EXPECT_EQ(0U, size);
190 req->Release();
191}
192
193TEST_F(AsyncHttpRequestTest, DISABLED_TestGetToInvalidHostname) {
194 AsyncHttpRequest* req = CreateGetRequest(
195 "invalid", server().address().port(),
196 kServerGetPath);
197 req->Start();
198 EXPECT_TRUE_WAIT(done(), 5000);
199 size_t size;
200 EXPECT_EQ(500U, req->response().scode);
201 ASSERT_TRUE(req->response().document);
202 req->response().document->GetSize(&size);
203 EXPECT_EQ(0U, size);
204 req->Release();
205}
206
207TEST_F(AsyncHttpRequestTest, TestPostSuccess) {
208 AsyncHttpRequest* req = CreatePostRequest(
209 kServerHostnameAddr.hostname(), server().address().port(),
210 kServerPostPath, "text/plain", new MemoryStream("abcd1234"));
211 req->Start();
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);
219 req->Release();
220}
221
222// Ensure that we shut down properly even if work is outstanding.
223TEST_F(AsyncHttpRequestTest, TestCancel) {
224 AsyncHttpRequest* req = CreateGetRequest(
225 kServerHostnameAddr.hostname(), server().address().port(),
226 kServerGetPath);
227 req->Start();
228 req->Destroy(true);
229}
230
231TEST_F(AsyncHttpRequestTest, TestGetSuccessDelay) {
232 AsyncHttpRequest* req = CreateGetRequest(
233 kServerHostnameAddr.hostname(), server().address().port(),
234 kServerGetPath);
235 req->set_start_delay(10); // Delay 10ms.
236 req->Start();
237 Thread::SleepMs(5);
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);
247 req->Release();
248}
249
250} // namespace talk_base