• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 #include <vector>
6 
7 #include "net/url_request/url_request_test_job.h"
8 
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"
15 
16 namespace net {
17 
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
20 // object.
21 static std::vector< scoped_refptr<URLRequestTestJob> > g_pending_jobs;
22 
23 // static getters for known URLs
test_url_1()24 GURL URLRequestTestJob::test_url_1() {
25   return GURL("test:url1");
26 }
test_url_2()27 GURL URLRequestTestJob::test_url_2() {
28   return GURL("test:url2");
29 }
test_url_3()30 GURL URLRequestTestJob::test_url_3() {
31   return GURL("test:url3");
32 }
test_url_error()33 GURL URLRequestTestJob::test_url_error() {
34   return GURL("test:error");
35 }
36 
37 // static getters for known URL responses
test_data_1()38 std::string URLRequestTestJob::test_data_1() {
39   return std::string("<html><title>Test One</title></html>");
40 }
test_data_2()41 std::string URLRequestTestJob::test_data_2() {
42   return std::string("<html><title>Test Two Two</title></html>");
43 }
test_data_3()44 std::string URLRequestTestJob::test_data_3() {
45   return std::string("<html><title>Test Three Three Three</title></html>");
46 }
47 
48 // static getter for simple response headers
test_headers()49 std::string URLRequestTestJob::test_headers() {
50   const char headers[] =
51       "HTTP/1.1 200 OK\0"
52       "Content-type: text/html\0"
53       "\0";
54   return std::string(headers, arraysize(headers));
55 }
56 
57 // static getter for redirect response headers
test_redirect_headers()58 std::string URLRequestTestJob::test_redirect_headers() {
59   const char headers[] =
60       "HTTP/1.1 302 MOVED\0"
61       "Location: somewhere\0"
62       "\0";
63   return std::string(headers, arraysize(headers));
64 }
65 
66 // static getter for error response headers
test_error_headers()67 std::string URLRequestTestJob::test_error_headers() {
68   const char headers[] =
69       "HTTP/1.1 500 BOO HOO\0"
70       "\0";
71   return std::string(headers, arraysize(headers));
72 }
73 
74 // static
Factory(URLRequest * request,const std::string & scheme)75 URLRequestJob* URLRequestTestJob::Factory(URLRequest* request,
76                                           const std::string& scheme) {
77   return new URLRequestTestJob(request);
78 }
79 
URLRequestTestJob(URLRequest * request)80 URLRequestTestJob::URLRequestTestJob(URLRequest* request)
81     : URLRequestJob(request),
82       auto_advance_(false),
83       stage_(WAITING),
84       offset_(0),
85       async_buf_(NULL),
86       async_buf_size_(0) {
87 }
88 
URLRequestTestJob(URLRequest * request,bool auto_advance)89 URLRequestTestJob::URLRequestTestJob(URLRequest* request,
90                                      bool auto_advance)
91     : URLRequestJob(request),
92       auto_advance_(auto_advance),
93       stage_(WAITING),
94       offset_(0),
95       async_buf_(NULL),
96       async_buf_size_(0) {
97 }
98 
URLRequestTestJob(URLRequest * request,const std::string & response_headers,const std::string & response_data,bool auto_advance)99 URLRequestTestJob::URLRequestTestJob(URLRequest* request,
100                                      const std::string& response_headers,
101                                      const std::string& response_data,
102                                      bool auto_advance)
103     : URLRequestJob(request),
104       auto_advance_(auto_advance),
105       stage_(WAITING),
106       response_headers_(new HttpResponseHeaders(response_headers)),
107       response_data_(response_data),
108       offset_(0),
109       async_buf_(NULL),
110       async_buf_size_(0) {
111 }
112 
~URLRequestTestJob()113 URLRequestTestJob::~URLRequestTestJob() {
114 }
115 
GetMimeType(std::string * mime_type) const116 bool URLRequestTestJob::GetMimeType(std::string* mime_type) const {
117   DCHECK(mime_type);
118   if (!response_headers_)
119     return false;
120   return response_headers_->GetMimeType(mime_type);
121 }
122 
Start()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));
128 }
129 
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();
140     } else {
141       // unexpected url, return error
142       // FIXME(brettw) we may want to use WININET errors or have some more types
143       // of errors
144       NotifyDone(URLRequestStatus(URLRequestStatus::FAILED,
145                                   ERR_INVALID_URL));
146       // FIXME(brettw): this should emulate a network error, and not just fail
147       // initiating a connection
148       return;
149     }
150   }
151 
152   AdvanceJob();
153 
154   this->NotifyHeadersComplete();
155 }
156 
ReadRawData(IOBuffer * buf,int buf_size,int * bytes_read)157 bool URLRequestTestJob::ReadRawData(IOBuffer* buf, int buf_size,
158                                     int *bytes_read) {
159   if (stage_ == WAITING) {
160     async_buf_ = buf;
161     async_buf_size_ = buf_size;
162     SetStatus(URLRequestStatus(URLRequestStatus::IO_PENDING, 0));
163     return false;
164   }
165 
166   DCHECK(bytes_read);
167   *bytes_read = 0;
168 
169   if (offset_ >= static_cast<int>(response_data_.length())) {
170     return true;  // done reading
171   }
172 
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_;
176 
177   memcpy(buf->data(), &response_data_.c_str()[offset_], to_read);
178   offset_ += to_read;
179 
180   *bytes_read = to_read;
181   return true;
182 }
183 
GetResponseInfo(HttpResponseInfo * info)184 void URLRequestTestJob::GetResponseInfo(HttpResponseInfo* info) {
185   if (response_headers_)
186     info->headers = response_headers_;
187 }
188 
GetResponseCode() const189 int URLRequestTestJob::GetResponseCode() const {
190   if (response_headers_)
191     return response_headers_->response_code();
192   return -1;
193 }
194 
IsRedirectResponse(GURL * location,int * http_status_code)195 bool URLRequestTestJob::IsRedirectResponse(GURL* location,
196                                            int* http_status_code) {
197   if (!response_headers_)
198     return false;
199 
200   std::string value;
201   if (!response_headers_->IsRedirect(&value))
202     return false;
203 
204   *location = request_->url().Resolve(value);
205   *http_status_code = response_headers_->response_code();
206   return true;
207 }
208 
209 
Kill()210 void URLRequestTestJob::Kill() {
211   stage_ = DONE;
212   URLRequestJob::Kill();
213 }
214 
ProcessNextOperation()215 void URLRequestTestJob::ProcessNextOperation() {
216   switch (stage_) {
217     case WAITING:
218       stage_ = DATA_AVAILABLE;
219       // OK if ReadRawData wasn't called yet.
220       if (async_buf_) {
221         int bytes_read;
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);
226       }
227       break;
228     case DATA_AVAILABLE:
229       stage_ = ALL_DATA;  // done sending data
230       break;
231     case ALL_DATA:
232       stage_ = DONE;
233       return;
234     case DONE:
235       return;
236     default:
237       NOTREACHED() << "Invalid stage";
238       return;
239   }
240   AdvanceJob();
241 }
242 
AdvanceJob()243 void URLRequestTestJob::AdvanceJob() {
244   if (auto_advance_) {
245     MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
246          this, &URLRequestTestJob::ProcessNextOperation));
247     return;
248   }
249   g_pending_jobs.push_back(scoped_refptr<URLRequestTestJob>(this));
250 }
251 
252 // static
ProcessOnePendingMessage()253 bool URLRequestTestJob::ProcessOnePendingMessage() {
254   if (g_pending_jobs.empty())
255     return false;
256 
257   scoped_refptr<URLRequestTestJob> next_job(g_pending_jobs[0]);
258   g_pending_jobs.erase(g_pending_jobs.begin());
259 
260   DCHECK(!next_job->auto_advance());  // auto_advance jobs should be in this q
261   next_job->ProcessNextOperation();
262   return true;
263 }
264 
265 }  // namespace net
266