Chromium Code Reviews| 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(HandleReadCompletion(bytes_read)); |
| 119 // completion of the request is detected in DoRead(). | 112 } |
| 120 | 113 |
| 121 if (request->status().is_success()) | 114 int SdchDictionaryFetcher::HandleReadCompletion(int bytes_read) { |
|
mmenke
2015/01/26 16:40:12
I suggest moving the append and state transition i
Randy Smith (Not in Mondays)
2015/01/26 19:52:21
Done.
| |
| 115 int error = current_request_->status().error(); | |
| 116 if (current_request_->status().is_success() && bytes_read < 0) { | |
|
mmenke
2015/01/26 16:40:12
Can this even happen?
Randy Smith (Not in Mondays)
2015/01/26 19:52:23
That's a fascinating question. I thought the answ
| |
| 117 error = current_request_->status().status() == URLRequestStatus::CANCELED | |
| 118 ? ERR_ABORTED | |
| 119 : ERR_FAILED; | |
| 120 current_request_->net_log().AddEventWithNetErrorCode( | |
| 121 NetLog::TYPE_SDCH_DICTIONARY_FETCH_IMPLIED_ERROR, error); | |
| 122 } | |
| 123 | |
| 124 if (error == OK && bytes_read > 0) | |
| 122 dictionary_.append(buffer_->data(), bytes_read); | 125 dictionary_.append(buffer_->data(), bytes_read); |
| 123 | 126 |
| 124 // If this function was synchronously called, the containing | 127 if (error == OK && bytes_read == 0) |
| 125 // state machine loop will handle the state transition. Otherwise, | 128 next_state_ = STATE_REQUEST_COMPLETE; |
| 126 // restart the state machine loop. | |
| 127 if (in_loop_) | |
| 128 return; | |
| 129 | 129 |
| 130 DoLoop(request->status().error()); | 130 return error; |
| 131 } | 131 } |
| 132 | 132 |
| 133 int SdchDictionaryFetcher::DoLoop(int rv) { | 133 int SdchDictionaryFetcher::DoLoop(int rv) { |
| 134 DCHECK(!in_loop_); | 134 DCHECK(!in_loop_); |
| 135 base::AutoReset<bool> auto_reset_in_loop(&in_loop_, true); | 135 base::AutoReset<bool> auto_reset_in_loop(&in_loop_, true); |
| 136 | 136 |
| 137 do { | 137 do { |
| 138 State state = next_state_; | 138 State state = next_state_; |
| 139 next_state_ = STATE_NONE; | 139 next_state_ = STATE_NONE; |
| 140 switch (state) { | 140 switch (state) { |
| 141 case STATE_IDLE: | 141 case STATE_SEND_REQUEST: |
| 142 rv = DoDispatchRequest(rv); | 142 rv = DoSendRequest(rv); |
| 143 break; | 143 break; |
| 144 case STATE_REQUEST_STARTED: | 144 case STATE_SEND_REQUEST_COMPLETE: |
| 145 rv = DoRequestStarted(rv); | 145 rv = DoSendRequestComplete(rv); |
| 146 break; | 146 break; |
| 147 case STATE_REQUEST_READING: | 147 case STATE_READ_BODY: |
| 148 rv = DoRead(rv); | 148 rv = DoReadBody(rv); |
| 149 break; | |
| 150 case STATE_READ_BODY_COMPLETE: | |
| 151 rv = DoReadBodyComplete(rv); | |
| 149 break; | 152 break; |
| 150 case STATE_REQUEST_COMPLETE: | 153 case STATE_REQUEST_COMPLETE: |
| 151 rv = DoCompleteRequest(rv); | 154 rv = DoCompleteRequest(rv); |
| 152 break; | 155 break; |
| 153 case STATE_NONE: | 156 case STATE_NONE: |
| 154 NOTREACHED(); | 157 NOTREACHED(); |
| 155 } | 158 } |
| 156 } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE); | 159 } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE); |
| 157 | 160 |
| 158 return rv; | 161 return rv; |
| 159 } | 162 } |
| 160 | 163 |
| 161 int SdchDictionaryFetcher::DoDispatchRequest(int rv) { | 164 int SdchDictionaryFetcher::DoSendRequest(int rv) { |
| 162 DCHECK(CalledOnValidThread()); | 165 DCHECK(CalledOnValidThread()); |
| 163 | 166 |
| 164 // |rv| is ignored, as the result from the previous request doesn't | 167 // |rv| is ignored, as the result from the previous request doesn't |
| 165 // affect the next request. | 168 // affect the next request. |
| 166 | 169 |
| 167 if (fetch_queue_.empty() || current_request_.get()) { | 170 if (fetch_queue_.empty() || current_request_.get()) { |
| 168 next_state_ = STATE_NONE; | 171 next_state_ = STATE_NONE; |
| 169 return OK; | 172 return OK; |
| 170 } | 173 } |
| 171 | 174 |
| 175 next_state_ = STATE_SEND_REQUEST_COMPLETE; | |
| 176 | |
| 172 current_request_ = | 177 current_request_ = |
| 173 context_->CreateRequest(fetch_queue_.front(), IDLE, this, NULL); | 178 context_->CreateRequest(fetch_queue_.front(), IDLE, this, NULL); |
| 174 current_request_->SetLoadFlags(LOAD_DO_NOT_SEND_COOKIES | | 179 current_request_->SetLoadFlags(LOAD_DO_NOT_SEND_COOKIES | |
| 175 LOAD_DO_NOT_SAVE_COOKIES); | 180 LOAD_DO_NOT_SAVE_COOKIES); |
| 176 buffer_ = new IOBuffer(kBufferSize); | 181 buffer_ = new IOBuffer(kBufferSize); |
| 177 fetch_queue_.pop(); | 182 fetch_queue_.pop(); |
| 178 | 183 |
| 179 next_state_ = STATE_REQUEST_STARTED; | |
| 180 current_request_->Start(); | 184 current_request_->Start(); |
| 181 current_request_->net_log().AddEvent(NetLog::TYPE_SDCH_DICTIONARY_FETCH); | 185 current_request_->net_log().AddEvent(NetLog::TYPE_SDCH_DICTIONARY_FETCH); |
| 182 | 186 |
| 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; | 187 return ERR_IO_PENDING; |
| 198 } | 188 } |
| 199 | 189 |
| 200 int SdchDictionaryFetcher::DoRead(int rv) { | 190 int SdchDictionaryFetcher::DoSendRequestComplete(int rv) { |
| 201 DCHECK(CalledOnValidThread()); | 191 DCHECK(CalledOnValidThread()); |
| 202 | 192 |
| 203 // If there's been an error, abort the current request. | 193 // If there's been an error, abort the current request. |
| 204 if (rv != OK) { | 194 if (rv != OK) { |
| 205 current_request_.reset(); | 195 current_request_.reset(); |
| 206 buffer_ = NULL; | 196 buffer_ = NULL; |
| 207 next_state_ = STATE_IDLE; | 197 next_state_ = STATE_SEND_REQUEST; |
| 208 | 198 |
| 209 return OK; | 199 return OK; |
| 210 } | 200 } |
| 211 | 201 |
| 212 next_state_ = STATE_REQUEST_READING; | 202 next_state_ = STATE_READ_BODY; |
| 203 return OK; | |
| 204 } | |
| 205 | |
| 206 int SdchDictionaryFetcher::DoReadBody(int rv) { | |
| 207 DCHECK(CalledOnValidThread()); | |
| 208 | |
| 209 // If there's been an error, abort the current request. | |
| 210 if (rv != OK) { | |
| 211 current_request_.reset(); | |
| 212 buffer_ = NULL; | |
| 213 next_state_ = STATE_SEND_REQUEST; | |
| 214 | |
| 215 return OK; | |
| 216 } | |
| 217 | |
| 218 next_state_ = STATE_READ_BODY_COMPLETE; | |
| 213 int bytes_read = 0; | 219 int bytes_read = 0; |
| 214 current_request_->Read(buffer_.get(), kBufferSize, &bytes_read); | 220 current_request_->Read(buffer_.get(), kBufferSize, &bytes_read); |
| 215 if (current_request_->status().is_io_pending()) | 221 if (current_request_->status().is_io_pending()) |
| 216 return ERR_IO_PENDING; | 222 return ERR_IO_PENDING; |
| 217 | 223 |
| 218 if (bytes_read < 0 || !current_request_->status().is_success()) { | 224 return HandleReadCompletion(bytes_read); |
| 219 if (current_request_->status().error() != OK) | 225 } |
| 220 return current_request_->status().error(); | |
| 221 | 226 |
| 222 // An error with request status of OK should not happen, | 227 int SdchDictionaryFetcher::DoReadBodyComplete(int rv) { |
| 223 // but there's enough machinery underneath URLRequest::Read() | 228 DCHECK(CalledOnValidThread()); |
| 224 // that this routine checks for that case. | 229 |
| 225 net::Error error = | 230 // If there's been an error, abort the current request. |
| 226 current_request_->status().status() == URLRequestStatus::CANCELED ? | 231 if (rv != OK) { |
| 227 ERR_ABORTED : ERR_FAILED; | 232 current_request_.reset(); |
| 228 current_request_->net_log().AddEventWithNetErrorCode( | 233 buffer_ = NULL; |
| 229 NetLog::TYPE_SDCH_DICTIONARY_FETCH_IMPLIED_ERROR, error); | 234 next_state_ = STATE_SEND_REQUEST; |
| 230 return error; | 235 |
| 236 return OK; | |
| 231 } | 237 } |
| 232 | 238 |
| 233 if (bytes_read == 0) | 239 DCHECK(current_request_->status().is_success()); |
| 234 next_state_ = STATE_REQUEST_COMPLETE; | 240 |
| 235 else | 241 next_state_ = STATE_READ_BODY; |
| 236 dictionary_.append(buffer_->data(), bytes_read); | |
| 237 | 242 |
| 238 return OK; | 243 return OK; |
| 239 } | 244 } |
| 240 | 245 |
| 241 int SdchDictionaryFetcher::DoCompleteRequest(int rv) { | 246 int SdchDictionaryFetcher::DoCompleteRequest(int rv) { |
| 242 DCHECK(CalledOnValidThread()); | 247 DCHECK(CalledOnValidThread()); |
| 243 | 248 |
| 244 // If the dictionary was successfully fetched, add it to the manager. | 249 // HandleReadCompletion() only transitions to this state |
| 245 if (rv == OK) { | 250 // on success. |
| 246 dictionary_fetched_callback_.Run(dictionary_, current_request_->url(), | 251 DCHECK_EQ(OK, rv); |
| 247 current_request_->net_log()); | |
| 248 } | |
| 249 | 252 |
| 253 dictionary_fetched_callback_.Run(dictionary_, current_request_->url(), | |
| 254 current_request_->net_log()); | |
| 250 current_request_.reset(); | 255 current_request_.reset(); |
| 251 buffer_ = NULL; | 256 buffer_ = NULL; |
| 252 dictionary_.clear(); | 257 dictionary_.clear(); |
| 253 | 258 |
| 254 next_state_ = STATE_IDLE; | 259 next_state_ = STATE_SEND_REQUEST; |
| 255 | 260 |
| 256 return OK; | 261 return OK; |
| 257 } | 262 } |
| 258 | 263 |
| 259 } // namespace net | 264 } // namespace net |
| OLD | NEW |