Mercurial > projects > hoofbaby
comparison deps/Platinum/Source/Core/PltHttpClientTask.cpp @ 0:3425707ddbf6
Initial import (hopefully this mercurial stuff works...)
author | fraserofthenight |
---|---|
date | Mon, 06 Jul 2009 08:06:28 -0700 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:3425707ddbf6 |
---|---|
1 /***************************************************************** | |
2 | | |
3 | Platinum - HTTP Client Tasks | |
4 | | |
5 | Copyright (c) 2004-2008, Plutinosoft, LLC. | |
6 | All rights reserved. | |
7 | http://www.plutinosoft.com | |
8 | | |
9 | This program is free software; you can redistribute it and/or | |
10 | modify it under the terms of the GNU General Public License | |
11 | as published by the Free Software Foundation; either version 2 | |
12 | of the License, or (at your option) any later version. | |
13 | | |
14 | OEMs, ISVs, VARs and other distributors that combine and | |
15 | distribute commercially licensed software with Platinum software | |
16 | and do not wish to distribute the source code for the commercially | |
17 | licensed software under version 2, or (at your option) any later | |
18 | version, of the GNU General Public License (the "GPL") must enter | |
19 | into a commercial license agreement with Plutinosoft, LLC. | |
20 | | |
21 | This program is distributed in the hope that it will be useful, | |
22 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
23 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
24 | GNU General Public License for more details. | |
25 | | |
26 | You should have received a copy of the GNU General Public License | |
27 | along with this program; see the file LICENSE.txt. If not, write to | |
28 | the Free Software Foundation, Inc., | |
29 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |
30 | http://www.gnu.org/licenses/gpl-2.0.html | |
31 | | |
32 ****************************************************************/ | |
33 | |
34 /*---------------------------------------------------------------------- | |
35 | includes | |
36 +---------------------------------------------------------------------*/ | |
37 #include "PltHttpClientTask.h" | |
38 | |
39 NPT_SET_LOCAL_LOGGER("platinum.core.http.clienttask") | |
40 | |
41 /*---------------------------------------------------------------------- | |
42 | PLT_HttpTcpConnector::PLT_HttpTcpConnector | |
43 +---------------------------------------------------------------------*/ | |
44 PLT_HttpTcpConnector::PLT_HttpTcpConnector() : | |
45 NPT_HttpClient::Connector(), | |
46 m_Socket(new NPT_TcpClientSocket()) | |
47 { | |
48 } | |
49 | |
50 /*---------------------------------------------------------------------- | |
51 | PLT_HttpTcpConnector::Connect | |
52 +---------------------------------------------------------------------*/ | |
53 NPT_Result | |
54 PLT_HttpTcpConnector::Connect(const char* hostname, | |
55 NPT_UInt16 port, | |
56 NPT_Timeout connection_timeout, | |
57 NPT_Timeout io_timeout, | |
58 NPT_Timeout name_resolver_timeout, | |
59 NPT_InputStreamReference& input_stream, | |
60 NPT_OutputStreamReference& output_stream) | |
61 { | |
62 if (m_HostName == hostname && m_Port == port) { | |
63 input_stream = m_InputStream; | |
64 output_stream = m_OutputStream; | |
65 return NPT_SUCCESS; | |
66 } | |
67 | |
68 // get the address and port to which we need to connect | |
69 NPT_IpAddress address; | |
70 NPT_CHECK_FATAL(address.ResolveName(hostname, name_resolver_timeout)); | |
71 | |
72 // connect to the server | |
73 NPT_LOG_FINE_2("NPT_HttpTcpConnector::Connect - will connect to %s:%d\n", hostname, port); | |
74 m_Socket->SetReadTimeout(io_timeout); | |
75 m_Socket->SetWriteTimeout(io_timeout); | |
76 NPT_SocketAddress socket_address(address, port); | |
77 NPT_CHECK_FATAL(m_Socket->Connect(socket_address, connection_timeout)); | |
78 | |
79 // get and keep the streams | |
80 NPT_CHECK(m_Socket->GetInputStream(m_InputStream)); | |
81 NPT_CHECK(m_Socket->GetOutputStream(m_OutputStream)); | |
82 NPT_CHECK(m_Socket->GetInfo(m_SocketInfo)); | |
83 | |
84 m_HostName = hostname; | |
85 m_Port = port; | |
86 input_stream = m_InputStream; | |
87 output_stream = m_OutputStream; | |
88 return NPT_SUCCESS; | |
89 } | |
90 | |
91 /*---------------------------------------------------------------------- | |
92 | PLT_HttpClientSocketTask::PLT_HttpClientSocketTask | |
93 +---------------------------------------------------------------------*/ | |
94 PLT_HttpClientSocketTask::PLT_HttpClientSocketTask(NPT_HttpRequest* request, | |
95 bool wait_forever /* = false */) : | |
96 m_WaitForever(wait_forever), | |
97 m_Connector(NULL) | |
98 { | |
99 if (request) m_Requests.Push(request); | |
100 } | |
101 | |
102 /*---------------------------------------------------------------------- | |
103 | PLT_HttpClientSocketTask::~PLT_HttpClientSocketTask | |
104 +---------------------------------------------------------------------*/ | |
105 PLT_HttpClientSocketTask::~PLT_HttpClientSocketTask() | |
106 { | |
107 // delete any outstanding requests | |
108 NPT_HttpRequest* request; | |
109 while (NPT_SUCCEEDED(m_Requests.Pop(request, false))) { | |
110 delete request; | |
111 } | |
112 } | |
113 | |
114 /*---------------------------------------------------------------------- | |
115 | PLT_HttpServerSocketTask::AddRequest | |
116 +---------------------------------------------------------------------*/ | |
117 NPT_Result | |
118 PLT_HttpClientSocketTask::AddRequest(NPT_HttpRequest* request) | |
119 { | |
120 return m_Requests.Push(request); | |
121 } | |
122 | |
123 /*---------------------------------------------------------------------- | |
124 | PLT_HttpServerSocketTask::GetNextRequest | |
125 +---------------------------------------------------------------------*/ | |
126 NPT_Result | |
127 PLT_HttpClientSocketTask::GetNextRequest(NPT_HttpRequest*& request, NPT_Timeout timeout) | |
128 { | |
129 return m_Requests.Pop(request, timeout); | |
130 } | |
131 | |
132 /*---------------------------------------------------------------------- | |
133 | PLT_HttpServerSocketTask::SetConnector | |
134 +---------------------------------------------------------------------*/ | |
135 NPT_Result | |
136 PLT_HttpClientSocketTask::SetConnector(PLT_HttpTcpConnector* connector) | |
137 { | |
138 NPT_AutoLock autolock(m_ConnectorLock); | |
139 | |
140 if (IsAborting(0)) return NPT_ERROR_CONNECTION_ABORTED; | |
141 | |
142 // NPT_HttpClient will delete old connector and own the new one | |
143 m_Client.SetConnector(connector); | |
144 m_Connector = connector; | |
145 return NPT_SUCCESS; | |
146 } | |
147 | |
148 /*---------------------------------------------------------------------- | |
149 | PLT_HttpServerSocketTask::DoAbort | |
150 +---------------------------------------------------------------------*/ | |
151 void | |
152 PLT_HttpClientSocketTask::DoAbort() | |
153 { | |
154 NPT_AutoLock autolock(m_ConnectorLock); | |
155 if (m_Connector) m_Connector->Abort(); | |
156 } | |
157 | |
158 /*---------------------------------------------------------------------- | |
159 | PLT_HttpServerSocketTask::DoRun | |
160 +---------------------------------------------------------------------*/ | |
161 void | |
162 PLT_HttpClientSocketTask::DoRun() | |
163 { | |
164 NPT_HttpRequest* request; | |
165 NPT_HttpRequestContext context; | |
166 bool using_previous_connector; | |
167 NPT_Result res; | |
168 NPT_HttpResponse* response; | |
169 | |
170 using_previous_connector = false; | |
171 SetConnector(new PLT_HttpTcpConnector()); | |
172 | |
173 do { | |
174 // pop next request or wait for one for 100ms | |
175 if (NPT_SUCCEEDED(GetNextRequest(request, 100))) { | |
176 response = NULL; | |
177 retry: | |
178 // if body is not seekable, don't even try to | |
179 // reuse previous connector since in case it fails because | |
180 // server closed connection, we won't be able to | |
181 // rewind the body to resend the request | |
182 if (!PLT_HttpHelper::IsBodyStreamSeekable(*request) && using_previous_connector) { | |
183 using_previous_connector = false; | |
184 if (NPT_FAILED(SetConnector(new PLT_HttpTcpConnector()))) | |
185 goto abort; | |
186 } | |
187 | |
188 if (IsAborting(0)) goto abort; | |
189 | |
190 // send request | |
191 res = m_Client.SendRequest(*request, response); | |
192 | |
193 // retry only if we were reusing a previous connector | |
194 if (NPT_FAILED(res) && using_previous_connector) { | |
195 using_previous_connector = false; | |
196 if (NPT_FAILED(SetConnector(new PLT_HttpTcpConnector()))) | |
197 goto abort; | |
198 | |
199 // server may have closed socket on us | |
200 NPT_HttpEntity* entity = request->GetEntity(); | |
201 NPT_InputStreamReference input_stream; | |
202 | |
203 // rewind request body if any to be able to resend it | |
204 if (entity && NPT_SUCCEEDED(entity->GetInputStream(input_stream))) { | |
205 input_stream->Seek(0); | |
206 } | |
207 | |
208 goto retry; | |
209 } | |
210 | |
211 NPT_LOG_FINE_1("PLT_HttpClientSocketTask receiving: res = %d", res); | |
212 PLT_LOG_HTTP_MESSAGE(NPT_LOG_LEVEL_FINE, response); | |
213 | |
214 // callback to process response | |
215 NPT_SocketInfo info; | |
216 m_Connector->GetInfo(info); | |
217 context.SetLocalAddress(info.local_address); | |
218 context.SetRemoteAddress(info.remote_address); | |
219 ProcessResponse(res, request, context, response); | |
220 | |
221 // check if server says keep-alive to keep our connector | |
222 if (response && PLT_HttpHelper::IsConnectionKeepAlive(*response)) { | |
223 using_previous_connector = true; | |
224 } else { | |
225 using_previous_connector = false; | |
226 if (NPT_FAILED(SetConnector(new PLT_HttpTcpConnector()))) | |
227 goto abort; | |
228 } | |
229 | |
230 // cleanup | |
231 delete response; | |
232 response = NULL; | |
233 delete request; | |
234 request = NULL; | |
235 } | |
236 } while (m_WaitForever && !IsAborting(0)); | |
237 | |
238 abort: | |
239 if (request) delete request; | |
240 if (response) delete response; | |
241 } | |
242 | |
243 /*---------------------------------------------------------------------- | |
244 | PLT_HttpServerSocketTask::ProcessResponse | |
245 +---------------------------------------------------------------------*/ | |
246 NPT_Result | |
247 PLT_HttpClientSocketTask::ProcessResponse(NPT_Result res, | |
248 NPT_HttpRequest* request, | |
249 const NPT_HttpRequestContext& context, | |
250 NPT_HttpResponse* response) | |
251 { | |
252 NPT_COMPILER_UNUSED(request); | |
253 NPT_COMPILER_UNUSED(context); | |
254 | |
255 NPT_LOG_FINE_1("PLT_HttpClientSocketTask::ProcessResponse (result=%d)", res); | |
256 NPT_CHECK_WARNING(res); | |
257 | |
258 NPT_HttpEntity* entity; | |
259 NPT_InputStreamReference body; | |
260 if (!response || | |
261 !(entity = response->GetEntity()) || | |
262 NPT_FAILED(entity->GetInputStream(body))) { | |
263 return NPT_FAILURE; | |
264 } | |
265 | |
266 // dump body into memory (if no content-length specified, read until disconnection) | |
267 NPT_MemoryStream output; | |
268 NPT_CHECK_SEVERE(NPT_StreamToStreamCopy(*body, | |
269 output, | |
270 0, | |
271 entity->GetContentLength())); | |
272 | |
273 return NPT_SUCCESS; | |
274 } | |
275 | |
276 /*---------------------------------------------------------------------- | |
277 | PLT_FileHttpClientTask::ProcessResponse | |
278 +---------------------------------------------------------------------*/ | |
279 NPT_Result | |
280 PLT_FileHttpClientTask::ProcessResponse(NPT_Result res, | |
281 NPT_HttpRequest* request, | |
282 const NPT_HttpRequestContext& context, | |
283 NPT_HttpResponse* response) | |
284 { | |
285 NPT_COMPILER_UNUSED(res); | |
286 NPT_COMPILER_UNUSED(request); | |
287 NPT_COMPILER_UNUSED(context); | |
288 NPT_COMPILER_UNUSED(response); | |
289 | |
290 NPT_LOG_FINE_1("PLT_FileHttpClientTask::ProcessResponse (status=%d)\n", res); | |
291 return NPT_SUCCESS; | |
292 } |