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