OLD | NEW |
| (Empty) |
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 "net/http/winhttp_request_throttle.h" | |
6 | |
7 #include "base/logging.h" | |
8 #include "net/http/http_transaction_winhttp.h" | |
9 | |
10 namespace { | |
11 | |
12 // The arguments to a WinHttpSendRequest call. | |
13 struct SendRequestArgs { | |
14 SendRequestArgs() : request_handle(NULL), total_size(0), context(0) {} | |
15 | |
16 SendRequestArgs(HINTERNET handle, DWORD size, DWORD_PTR context_value) | |
17 : request_handle(handle), total_size(size), context(context_value) {} | |
18 | |
19 HINTERNET request_handle; | |
20 DWORD total_size; | |
21 DWORD_PTR context; | |
22 }; | |
23 | |
24 } // namespace | |
25 | |
26 namespace net { | |
27 | |
28 // Per-server queue for WinHttpSendRequest calls. | |
29 class WinHttpRequestThrottle::RequestQueue { | |
30 public: | |
31 RequestQueue() {} | |
32 | |
33 // Adds |args| to the end of the queue. | |
34 void PushBack(const SendRequestArgs& args) { queue_.push_back(args); } | |
35 | |
36 // If the queue is not empty, pops the first entry off the queue, saves it | |
37 // in |*args|, and returns true. If the queue is empty, returns false. | |
38 bool GetFront(SendRequestArgs* args); | |
39 | |
40 // If the queue has an entry containing |request_handle|, removes it and | |
41 // returns true. Otherwise, returns false. | |
42 bool Remove(HINTERNET request_handle); | |
43 | |
44 bool empty() const { return queue_.empty(); } | |
45 | |
46 private: | |
47 std::list<SendRequestArgs> queue_; | |
48 | |
49 DISALLOW_EVIL_CONSTRUCTORS(RequestQueue); | |
50 }; | |
51 | |
52 bool WinHttpRequestThrottle::RequestQueue::GetFront(SendRequestArgs* args) { | |
53 if (queue_.empty()) | |
54 return false; | |
55 *args = queue_.front(); | |
56 queue_.pop_front(); | |
57 return true; | |
58 } | |
59 | |
60 bool WinHttpRequestThrottle::RequestQueue::Remove(HINTERNET request_handle) { | |
61 std::list<SendRequestArgs>::iterator it; | |
62 for (it = queue_.begin(); it != queue_.end(); ++it) { | |
63 if (it->request_handle == request_handle) { | |
64 queue_.erase(it); | |
65 return true; | |
66 } | |
67 } | |
68 return false; | |
69 } | |
70 | |
71 WinHttpRequestThrottle::~WinHttpRequestThrottle() { | |
72 #ifndef NDEBUG | |
73 ThrottleMap::const_iterator throttle_iter = throttles_.begin(); | |
74 for (; throttle_iter != throttles_.end(); ++throttle_iter) { | |
75 const PerServerThrottle& throttle = throttle_iter->second; | |
76 DCHECK(throttle.num_requests == 0); | |
77 DCHECK(!throttle.request_queue.get() || throttle.request_queue->empty()); | |
78 } | |
79 #endif | |
80 } | |
81 | |
82 BOOL WinHttpRequestThrottle::SubmitRequest(const std::string &server, | |
83 HINTERNET request_handle, | |
84 DWORD total_size, | |
85 DWORD_PTR context) { | |
86 PerServerThrottle& throttle = throttles_[server]; | |
87 DCHECK(throttle.num_requests >= 0 && | |
88 throttle.num_requests <= kMaxConnectionsPerServer); | |
89 if (throttle.num_requests >= kMaxConnectionsPerServer) { | |
90 if (!throttle.request_queue.get()) | |
91 throttle.request_queue.reset(new RequestQueue); | |
92 SendRequestArgs args(request_handle, total_size, context); | |
93 throttle.request_queue->PushBack(args); | |
94 return TRUE; | |
95 } | |
96 | |
97 BOOL ok = SendRequest(request_handle, total_size, context, false); | |
98 if (ok) | |
99 throttle.num_requests += 1; | |
100 return ok; | |
101 } | |
102 | |
103 void WinHttpRequestThrottle::NotifyRequestDone(const std::string& server) { | |
104 PerServerThrottle& throttle = throttles_[server]; | |
105 DCHECK(throttle.num_requests > 0 && | |
106 throttle.num_requests <= kMaxConnectionsPerServer); | |
107 throttle.num_requests -= 1; | |
108 SendRequestArgs args; | |
109 if (throttle.request_queue.get() && | |
110 throttle.request_queue->GetFront(&args)) { | |
111 throttle.num_requests += 1; | |
112 SendRequest(args.request_handle, args.total_size, args.context, true); | |
113 } | |
114 if (throttles_.size() > static_cast<size_t>(kGarbageCollectionThreshold)) | |
115 GarbageCollect(); | |
116 } | |
117 | |
118 void WinHttpRequestThrottle::RemoveRequest(const std::string& server, | |
119 HINTERNET request_handle) { | |
120 PerServerThrottle& throttle = throttles_[server]; | |
121 if (throttle.request_queue.get() && | |
122 throttle.request_queue->Remove(request_handle)) | |
123 return; | |
124 NotifyRequestDone(server); | |
125 } | |
126 | |
127 BOOL WinHttpRequestThrottle::SendRequest(HINTERNET request_handle, | |
128 DWORD total_size, | |
129 DWORD_PTR context, | |
130 bool report_async_error) { | |
131 BOOL ok = WinHttpSendRequest(request_handle, | |
132 WINHTTP_NO_ADDITIONAL_HEADERS, | |
133 0, | |
134 WINHTTP_NO_REQUEST_DATA, | |
135 0, | |
136 total_size, | |
137 context); | |
138 if (!ok && report_async_error) { | |
139 WINHTTP_ASYNC_RESULT async_result = { API_SEND_REQUEST, GetLastError() }; | |
140 HttpTransactionWinHttp::StatusCallback( | |
141 request_handle, context, | |
142 WINHTTP_CALLBACK_STATUS_REQUEST_ERROR, | |
143 &async_result, sizeof(async_result)); | |
144 } | |
145 return ok; | |
146 } | |
147 | |
148 WinHttpRequestThrottle::PerServerThrottle::PerServerThrottle() | |
149 : num_requests(0) { | |
150 } | |
151 | |
152 WinHttpRequestThrottle::PerServerThrottle::~PerServerThrottle() { | |
153 } | |
154 | |
155 // static | |
156 const int WinHttpRequestThrottle::kMaxConnectionsPerServer = 6; | |
157 | |
158 // static | |
159 const int WinHttpRequestThrottle::kGarbageCollectionThreshold = 64; | |
160 | |
161 void WinHttpRequestThrottle::GarbageCollect() { | |
162 ThrottleMap::iterator throttle_iter = throttles_.begin(); | |
163 while (throttle_iter != throttles_.end()) { | |
164 PerServerThrottle& throttle = throttle_iter->second; | |
165 if (throttle.num_requests == 0 && | |
166 (!throttle.request_queue.get() || throttle.request_queue->empty())) { | |
167 // Erase the current item but keep the iterator valid. | |
168 throttles_.erase(throttle_iter++); | |
169 } else { | |
170 ++throttle_iter; | |
171 } | |
172 } | |
173 } | |
174 | |
175 } // namespace net | |
176 | |
OLD | NEW |