OLD | NEW |
---|---|
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "net/url_request/sdch_dictionary_fetcher.h" | 5 #include "net/url_request/sdch_dictionary_fetcher.h" |
6 | 6 |
7 #include <stdint.h> | 7 #include <stdint.h> |
8 | 8 |
9 #include "base/auto_reset.h" | 9 #include "base/auto_reset.h" |
10 #include "base/bind.h" | 10 #include "base/bind.h" |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
53 // TODO(rdsmith): log this error to the net log of the URLRequest | 53 // TODO(rdsmith): log this error to the net log of the URLRequest |
54 // initiating this fetch, once URLRequest will be passed here. | 54 // initiating this fetch, once URLRequest will be passed here. |
55 SdchManager::SdchErrorRecovery( | 55 SdchManager::SdchErrorRecovery( |
56 SDCH_DICTIONARY_PREVIOUSLY_SCHEDULED_TO_DOWNLOAD); | 56 SDCH_DICTIONARY_PREVIOUSLY_SCHEDULED_TO_DOWNLOAD); |
57 return; | 57 return; |
58 } | 58 } |
59 | 59 |
60 attempted_load_.insert(dictionary_url); | 60 attempted_load_.insert(dictionary_url); |
61 fetch_queue_.push(dictionary_url); | 61 fetch_queue_.push(dictionary_url); |
62 | 62 |
63 next_state_ = STATE_IDLE; | 63 next_state_ = STATE_SEND_REQUEST; |
64 | 64 |
65 // There are no callbacks to user code from the dictionary fetcher, | 65 // There are no callbacks to user code from the dictionary fetcher, |
66 // and Schedule() is only called from user code, so this call to DoLoop() | 66 // and Schedule() is only called from user code, so this call to DoLoop() |
67 // does not require an |if (in_loop_) return;| guard. | 67 // does not require an |if (in_loop_) return;| guard. |
68 DoLoop(OK); | 68 DoLoop(OK); |
69 } | 69 } |
70 | 70 |
71 void SdchDictionaryFetcher::Cancel() { | 71 void SdchDictionaryFetcher::Cancel() { |
72 DCHECK(CalledOnValidThread()); | 72 DCHECK(CalledOnValidThread()); |
73 | 73 |
74 next_state_ = STATE_NONE; | 74 next_state_ = STATE_NONE; |
75 | 75 |
76 while (!fetch_queue_.empty()) | 76 while (!fetch_queue_.empty()) |
77 fetch_queue_.pop(); | 77 fetch_queue_.pop(); |
78 attempted_load_.clear(); | 78 attempted_load_.clear(); |
79 weak_factory_.InvalidateWeakPtrs(); | 79 weak_factory_.InvalidateWeakPtrs(); |
80 current_request_.reset(NULL); | 80 current_request_.reset(NULL); |
81 buffer_ = NULL; | 81 buffer_ = NULL; |
82 dictionary_.clear(); | 82 dictionary_.clear(); |
83 } | 83 } |
84 | 84 |
85 void SdchDictionaryFetcher::OnResponseStarted(URLRequest* request) { | 85 void SdchDictionaryFetcher::OnResponseStarted(URLRequest* request) { |
86 // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed. | 86 // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed. |
87 tracked_objects::ScopedTracker tracking_profile( | 87 tracked_objects::ScopedTracker tracking_profile( |
88 FROM_HERE_WITH_EXPLICIT_FUNCTION( | 88 FROM_HERE_WITH_EXPLICIT_FUNCTION( |
89 "423948 SdchDictionaryFetcher::OnResponseStarted")); | 89 "423948 SdchDictionaryFetcher::OnResponseStarted")); |
90 | 90 |
91 DCHECK(CalledOnValidThread()); | 91 DCHECK(CalledOnValidThread()); |
92 DCHECK_EQ(request, current_request_.get()); | 92 DCHECK_EQ(request, current_request_.get()); |
93 DCHECK_EQ(next_state_, STATE_REQUEST_STARTED); | 93 DCHECK_EQ(next_state_, STATE_SEND_REQUEST_COMPLETE); |
94 | 94 DCHECK(!in_loop_); |
95 // The response has started, so the stream can be read from. | |
96 next_state_ = STATE_REQUEST_READING; | |
97 | |
98 // If this function was synchronously called, the containing | |
99 // state machine loop will handle the state transition. Otherwise, | |
100 // restart the state machine loop. | |
101 if (in_loop_) | |
102 return; | |
103 | 95 |
104 DoLoop(request->status().error()); | 96 DoLoop(request->status().error()); |
105 } | 97 } |
106 | 98 |
107 void SdchDictionaryFetcher::OnReadCompleted(URLRequest* request, | 99 void SdchDictionaryFetcher::OnReadCompleted(URLRequest* request, |
108 int bytes_read) { | 100 int bytes_read) { |
109 // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed. | 101 // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed. |
110 tracked_objects::ScopedTracker tracking_profile( | 102 tracked_objects::ScopedTracker tracking_profile( |
111 FROM_HERE_WITH_EXPLICIT_FUNCTION( | 103 FROM_HERE_WITH_EXPLICIT_FUNCTION( |
112 "423948 SdchDictionaryFetcher::OnReadCompleted")); | 104 "423948 SdchDictionaryFetcher::OnReadCompleted")); |
113 | 105 |
114 DCHECK(CalledOnValidThread()); | 106 DCHECK(CalledOnValidThread()); |
115 DCHECK_EQ(request, current_request_.get()); | 107 DCHECK_EQ(request, current_request_.get()); |
116 DCHECK_EQ(next_state_, STATE_REQUEST_READING); | 108 DCHECK_EQ(next_state_, STATE_READ_BODY_COMPLETE); |
109 DCHECK(!in_loop_); | |
117 | 110 |
118 // No state transition is required in this function; the | 111 DoLoop(GetReadResult(bytes_read)); |
119 // completion of the request is detected in DoRead(). | 112 } |
120 | 113 |
121 if (request->status().is_success()) | 114 int SdchDictionaryFetcher::GetReadResult(int bytes_read) { |
mmenke
2015/01/26 20:14:25
optional: May be clearer as a static method that
Randy Smith (Not in Mondays)
2015/01/26 22:39:54
Done.
| |
122 dictionary_.append(buffer_->data(), bytes_read); | 115 int error = current_request_->status().error(); |
116 if (current_request_->status().is_success() && bytes_read < 0) { | |
117 error = current_request_->status().status() == URLRequestStatus::CANCELED | |
118 ? ERR_ABORTED | |
119 : ERR_FAILED; | |
mmenke
2015/01/26 20:14:25
This code is strange. If current_request_->status
mmenke
2015/01/26 20:25:44
Oh...you're right...It can actually do that, with
Randy Smith (Not in Mondays)
2015/01/26 22:39:54
Acknowledged.
Randy Smith (Not in Mondays)
2015/01/26 22:39:54
So if you want me to skip the netlog event I'm hap
mmenke
2015/01/30 16:20:43
I thought the issue was URLRequest::Read returning
| |
120 current_request_->net_log().AddEventWithNetErrorCode( | |
121 NetLog::TYPE_SDCH_DICTIONARY_FETCH_IMPLIED_ERROR, error); | |
mmenke
2015/01/26 20:14:25
Shouldn't we be logging all errors, not just ones
Randy Smith (Not in Mondays)
2015/01/26 22:39:54
This logging was breadcrumbs from trying to figure
| |
122 } | |
123 | 123 |
124 // If this function was synchronously called, the containing | 124 if (error == OK) |
125 // state machine loop will handle the state transition. Otherwise, | 125 error = bytes_read; |
mmenke
2015/01/26 20:14:25
"error = bytes_read" seems a little weird. Maybe
Randy Smith (Not in Mondays)
2015/01/26 22:39:54
Done.
| |
126 // restart the state machine loop. | |
127 if (in_loop_) | |
128 return; | |
129 | 126 |
130 DoLoop(request->status().error()); | 127 return error; |
131 } | 128 } |
132 | 129 |
133 int SdchDictionaryFetcher::DoLoop(int rv) { | 130 int SdchDictionaryFetcher::DoLoop(int rv) { |
134 DCHECK(!in_loop_); | 131 DCHECK(!in_loop_); |
135 base::AutoReset<bool> auto_reset_in_loop(&in_loop_, true); | 132 base::AutoReset<bool> auto_reset_in_loop(&in_loop_, true); |
136 | 133 |
137 do { | 134 do { |
138 State state = next_state_; | 135 State state = next_state_; |
139 next_state_ = STATE_NONE; | 136 next_state_ = STATE_NONE; |
140 switch (state) { | 137 switch (state) { |
141 case STATE_IDLE: | 138 case STATE_SEND_REQUEST: |
142 rv = DoDispatchRequest(rv); | 139 rv = DoSendRequest(rv); |
143 break; | 140 break; |
144 case STATE_REQUEST_STARTED: | 141 case STATE_SEND_REQUEST_COMPLETE: |
145 rv = DoRequestStarted(rv); | 142 rv = DoSendRequestComplete(rv); |
146 break; | 143 break; |
147 case STATE_REQUEST_READING: | 144 case STATE_READ_BODY: |
148 rv = DoRead(rv); | 145 rv = DoReadBody(rv); |
146 break; | |
147 case STATE_READ_BODY_COMPLETE: | |
148 rv = DoReadBodyComplete(rv); | |
149 break; | 149 break; |
150 case STATE_REQUEST_COMPLETE: | 150 case STATE_REQUEST_COMPLETE: |
151 rv = DoCompleteRequest(rv); | 151 rv = DoCompleteRequest(rv); |
152 break; | 152 break; |
153 case STATE_NONE: | 153 case STATE_NONE: |
154 NOTREACHED(); | 154 NOTREACHED(); |
155 } | 155 } |
156 } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE); | 156 } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE); |
157 | 157 |
158 return rv; | 158 return rv; |
159 } | 159 } |
160 | 160 |
161 int SdchDictionaryFetcher::DoDispatchRequest(int rv) { | 161 int SdchDictionaryFetcher::DoSendRequest(int rv) { |
162 DCHECK(CalledOnValidThread()); | 162 DCHECK(CalledOnValidThread()); |
163 | 163 |
164 // |rv| is ignored, as the result from the previous request doesn't | 164 // |rv| is ignored, as the result from the previous request doesn't |
165 // affect the next request. | 165 // affect the next request. |
166 | 166 |
167 if (fetch_queue_.empty() || current_request_.get()) { | 167 if (fetch_queue_.empty() || current_request_.get()) { |
168 next_state_ = STATE_NONE; | 168 next_state_ = STATE_NONE; |
169 return OK; | 169 return OK; |
170 } | 170 } |
171 | 171 |
172 next_state_ = STATE_SEND_REQUEST_COMPLETE; | |
173 | |
172 current_request_ = | 174 current_request_ = |
173 context_->CreateRequest(fetch_queue_.front(), IDLE, this, NULL); | 175 context_->CreateRequest(fetch_queue_.front(), IDLE, this, NULL); |
174 current_request_->SetLoadFlags(LOAD_DO_NOT_SEND_COOKIES | | 176 current_request_->SetLoadFlags(LOAD_DO_NOT_SEND_COOKIES | |
175 LOAD_DO_NOT_SAVE_COOKIES); | 177 LOAD_DO_NOT_SAVE_COOKIES); |
176 buffer_ = new IOBuffer(kBufferSize); | 178 buffer_ = new IOBuffer(kBufferSize); |
177 fetch_queue_.pop(); | 179 fetch_queue_.pop(); |
178 | 180 |
179 next_state_ = STATE_REQUEST_STARTED; | |
180 current_request_->Start(); | 181 current_request_->Start(); |
181 current_request_->net_log().AddEvent(NetLog::TYPE_SDCH_DICTIONARY_FETCH); | 182 current_request_->net_log().AddEvent(NetLog::TYPE_SDCH_DICTIONARY_FETCH); |
182 | 183 |
183 return OK; | |
184 } | |
185 | |
186 int SdchDictionaryFetcher::DoRequestStarted(int rv) { | |
187 DCHECK(CalledOnValidThread()); | |
188 DCHECK_EQ(rv, OK); // Can only come straight from above function. | |
189 | |
190 // The transition to STATE_REQUEST_READING occurs in the | |
191 // OnResponseStarted() callback triggered by URLRequest::Start() | |
192 // (called in DoDispatchRequest(), above). If that callback did not | |
193 // occur synchronously, this routine is executed; it returns ERR_IO_PENDING, | |
194 // indicating to the controlling loop that no further work should be done | |
195 // until the callback occurs (which will re-invoke DoLoop()). | |
196 next_state_ = STATE_REQUEST_STARTED; | |
197 return ERR_IO_PENDING; | 184 return ERR_IO_PENDING; |
198 } | 185 } |
199 | 186 |
200 int SdchDictionaryFetcher::DoRead(int rv) { | 187 int SdchDictionaryFetcher::DoSendRequestComplete(int rv) { |
201 DCHECK(CalledOnValidThread()); | 188 DCHECK(CalledOnValidThread()); |
202 | 189 |
203 // If there's been an error, abort the current request. | 190 // If there's been an error, abort the current request. |
204 if (rv != OK) { | 191 if (rv != OK) { |
205 current_request_.reset(); | 192 current_request_.reset(); |
206 buffer_ = NULL; | 193 buffer_ = NULL; |
207 next_state_ = STATE_IDLE; | 194 next_state_ = STATE_SEND_REQUEST; |
208 | 195 |
209 return OK; | 196 return OK; |
210 } | 197 } |
211 | 198 |
212 next_state_ = STATE_REQUEST_READING; | 199 next_state_ = STATE_READ_BODY; |
200 return OK; | |
201 } | |
202 | |
203 int SdchDictionaryFetcher::DoReadBody(int rv) { | |
204 DCHECK(CalledOnValidThread()); | |
205 | |
206 // If there's been an error, abort the current request. | |
207 if (rv != OK) { | |
208 current_request_.reset(); | |
209 buffer_ = NULL; | |
210 next_state_ = STATE_SEND_REQUEST; | |
211 | |
212 return OK; | |
213 } | |
214 | |
215 next_state_ = STATE_READ_BODY_COMPLETE; | |
213 int bytes_read = 0; | 216 int bytes_read = 0; |
214 current_request_->Read(buffer_.get(), kBufferSize, &bytes_read); | 217 current_request_->Read(buffer_.get(), kBufferSize, &bytes_read); |
215 if (current_request_->status().is_io_pending()) | 218 if (current_request_->status().is_io_pending()) |
216 return ERR_IO_PENDING; | 219 return ERR_IO_PENDING; |
217 | 220 |
218 if (bytes_read < 0 || !current_request_->status().is_success()) { | 221 return GetReadResult(bytes_read); |
219 if (current_request_->status().error() != OK) | 222 } |
220 return current_request_->status().error(); | |
221 | 223 |
222 // An error with request status of OK should not happen, | 224 int SdchDictionaryFetcher::DoReadBodyComplete(int rv) { |
223 // but there's enough machinery underneath URLRequest::Read() | 225 DCHECK(CalledOnValidThread()); |
224 // that this routine checks for that case. | 226 |
225 net::Error error = | 227 // If there's been an error, abort the current request. |
226 current_request_->status().status() == URLRequestStatus::CANCELED ? | 228 if (rv < 0) { |
227 ERR_ABORTED : ERR_FAILED; | 229 current_request_.reset(); |
228 current_request_->net_log().AddEventWithNetErrorCode( | 230 buffer_ = NULL; |
229 NetLog::TYPE_SDCH_DICTIONARY_FETCH_IMPLIED_ERROR, error); | 231 next_state_ = STATE_SEND_REQUEST; |
230 return error; | 232 |
233 return OK; | |
231 } | 234 } |
232 | 235 |
233 if (bytes_read == 0) | 236 DCHECK(current_request_->status().is_success()); |
237 | |
238 if (rv > 0) { | |
239 dictionary_.append(buffer_->data(), rv); | |
240 next_state_ = STATE_READ_BODY; | |
241 } else if (rv == 0) { | |
mmenke
2015/01/26 20:14:25
Should that be a DCHECK_EQ instead? Up to you, bu
Randy Smith (Not in Mondays)
2015/01/26 22:39:54
Looking at the logic, it was a bit too obvious to
| |
234 next_state_ = STATE_REQUEST_COMPLETE; | 242 next_state_ = STATE_REQUEST_COMPLETE; |
235 else | 243 } |
236 dictionary_.append(buffer_->data(), bytes_read); | |
237 | 244 |
238 return OK; | 245 return OK; |
239 } | 246 } |
240 | 247 |
241 int SdchDictionaryFetcher::DoCompleteRequest(int rv) { | 248 int SdchDictionaryFetcher::DoCompleteRequest(int rv) { |
242 DCHECK(CalledOnValidThread()); | 249 DCHECK(CalledOnValidThread()); |
243 | 250 |
244 // If the dictionary was successfully fetched, add it to the manager. | 251 // DoReadBodyComplete() only transitions to this state |
245 if (rv == OK) { | 252 // on success. |
246 dictionary_fetched_callback_.Run(dictionary_, current_request_->url(), | 253 DCHECK_EQ(OK, rv); |
247 current_request_->net_log()); | |
248 } | |
249 | 254 |
255 dictionary_fetched_callback_.Run(dictionary_, current_request_->url(), | |
256 current_request_->net_log()); | |
250 current_request_.reset(); | 257 current_request_.reset(); |
251 buffer_ = NULL; | 258 buffer_ = NULL; |
252 dictionary_.clear(); | 259 dictionary_.clear(); |
253 | 260 |
254 next_state_ = STATE_IDLE; | 261 next_state_ = STATE_SEND_REQUEST; |
255 | 262 |
256 return OK; | 263 return OK; |
257 } | 264 } |
258 | 265 |
259 } // namespace net | 266 } // namespace net |
OLD | NEW |