1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
7 #include "net/url_request/url_request_test_job.h"
9 #include "base/message_loop.h"
10 #include "base/string_util.h"
11 #include "net/base/io_buffer.h"
12 #include "net/base/net_errors.h"
13 #include "net/http/http_response_headers.h"
14 #include "net/url_request/url_request.h"
18 // This emulates the global message loop for the test URL request class, since
19 // this is only test code, it's probably not too dangerous to have this static
21 static std::vector
< scoped_refptr
<URLRequestTestJob
> > g_pending_jobs
;
23 // static getters for known URLs
24 GURL
URLRequestTestJob::test_url_1() {
25 return GURL("test:url1");
27 GURL
URLRequestTestJob::test_url_2() {
28 return GURL("test:url2");
30 GURL
URLRequestTestJob::test_url_3() {
31 return GURL("test:url3");
33 GURL
URLRequestTestJob::test_url_error() {
34 return GURL("test:error");
37 // static getters for known URL responses
38 std::string
URLRequestTestJob::test_data_1() {
39 return std::string("<html><title>Test One</title></html>");
41 std::string
URLRequestTestJob::test_data_2() {
42 return std::string("<html><title>Test Two Two</title></html>");
44 std::string
URLRequestTestJob::test_data_3() {
45 return std::string("<html><title>Test Three Three Three</title></html>");
48 // static getter for simple response headers
49 std::string
URLRequestTestJob::test_headers() {
50 const char headers
[] =
52 "Content-type: text/html\0"
54 return std::string(headers
, arraysize(headers
));
57 // static getter for redirect response headers
58 std::string
URLRequestTestJob::test_redirect_headers() {
59 const char headers
[] =
60 "HTTP/1.1 302 MOVED\0"
61 "Location: somewhere\0"
63 return std::string(headers
, arraysize(headers
));
66 // static getter for error response headers
67 std::string
URLRequestTestJob::test_error_headers() {
68 const char headers
[] =
69 "HTTP/1.1 500 BOO HOO\0"
71 return std::string(headers
, arraysize(headers
));
75 URLRequestJob
* URLRequestTestJob::Factory(URLRequest
* request
,
76 const std::string
& scheme
) {
77 return new URLRequestTestJob(request
);
80 URLRequestTestJob::URLRequestTestJob(URLRequest
* request
)
81 : URLRequestJob(request
),
89 URLRequestTestJob::URLRequestTestJob(URLRequest
* request
,
91 : URLRequestJob(request
),
92 auto_advance_(auto_advance
),
99 URLRequestTestJob::URLRequestTestJob(URLRequest
* request
,
100 const std::string
& response_headers
,
101 const std::string
& response_data
,
103 : URLRequestJob(request
),
104 auto_advance_(auto_advance
),
106 response_headers_(new HttpResponseHeaders(response_headers
)),
107 response_data_(response_data
),
113 URLRequestTestJob::~URLRequestTestJob() {
116 bool URLRequestTestJob::GetMimeType(std::string
* mime_type
) const {
118 if (!response_headers_
)
120 return response_headers_
->GetMimeType(mime_type
);
123 void URLRequestTestJob::Start() {
124 // Start reading asynchronously so that all error reporting and data
125 // callbacks happen as they would for network requests.
126 MessageLoop::current()->PostTask(FROM_HERE
, NewRunnableMethod(
127 this, &URLRequestTestJob::StartAsync
));
130 void URLRequestTestJob::StartAsync() {
131 if (!response_headers_
) {
132 response_headers_
= new HttpResponseHeaders(test_headers());
133 if (request_
->url().spec() == test_url_1().spec()) {
134 response_data_
= test_data_1();
135 stage_
= DATA_AVAILABLE
; // Simulate a synchronous response for this one.
136 } else if (request_
->url().spec() == test_url_2().spec()) {
137 response_data_
= test_data_2();
138 } else if (request_
->url().spec() == test_url_3().spec()) {
139 response_data_
= test_data_3();
141 // unexpected url, return error
142 // FIXME(brettw) we may want to use WININET errors or have some more types
144 NotifyDone(URLRequestStatus(URLRequestStatus::FAILED
,
146 // FIXME(brettw): this should emulate a network error, and not just fail
147 // initiating a connection
154 this->NotifyHeadersComplete();
157 bool URLRequestTestJob::ReadRawData(IOBuffer
* buf
, int buf_size
,
159 if (stage_
== WAITING
) {
161 async_buf_size_
= buf_size
;
162 SetStatus(URLRequestStatus(URLRequestStatus::IO_PENDING
, 0));
169 if (offset_
>= static_cast<int>(response_data_
.length())) {
170 return true; // done reading
173 int to_read
= buf_size
;
174 if (to_read
+ offset_
> static_cast<int>(response_data_
.length()))
175 to_read
= static_cast<int>(response_data_
.length()) - offset_
;
177 memcpy(buf
->data(), &response_data_
.c_str()[offset_
], to_read
);
180 *bytes_read
= to_read
;
184 void URLRequestTestJob::GetResponseInfo(HttpResponseInfo
* info
) {
185 if (response_headers_
)
186 info
->headers
= response_headers_
;
189 int URLRequestTestJob::GetResponseCode() const {
190 if (response_headers_
)
191 return response_headers_
->response_code();
195 bool URLRequestTestJob::IsRedirectResponse(GURL
* location
,
196 int* http_status_code
) {
197 if (!response_headers_
)
201 if (!response_headers_
->IsRedirect(&value
))
204 *location
= request_
->url().Resolve(value
);
205 *http_status_code
= response_headers_
->response_code();
210 void URLRequestTestJob::Kill() {
212 URLRequestJob::Kill();
215 void URLRequestTestJob::ProcessNextOperation() {
218 stage_
= DATA_AVAILABLE
;
219 // OK if ReadRawData wasn't called yet.
222 if (!ReadRawData(async_buf_
, async_buf_size_
, &bytes_read
))
223 NOTREACHED() << "This should not return false in DATA_AVAILABLE.";
224 SetStatus(URLRequestStatus()); // clear the io pending flag
225 NotifyReadComplete(bytes_read
);
229 stage_
= ALL_DATA
; // done sending data
237 NOTREACHED() << "Invalid stage";
243 void URLRequestTestJob::AdvanceJob() {
245 MessageLoop::current()->PostTask(FROM_HERE
, NewRunnableMethod(
246 this, &URLRequestTestJob::ProcessNextOperation
));
249 g_pending_jobs
.push_back(scoped_refptr
<URLRequestTestJob
>(this));
253 bool URLRequestTestJob::ProcessOnePendingMessage() {
254 if (g_pending_jobs
.empty())
257 scoped_refptr
<URLRequestTestJob
> next_job(g_pending_jobs
[0]);
258 g_pending_jobs
.erase(g_pending_jobs
.begin());
260 DCHECK(!next_job
->auto_advance()); // auto_advance jobs should be in this q
261 next_job
->ProcessNextOperation();