]>
Commit | Line | Data |
---|---|---|
f4ada568 | 1 | ///////////////////////////////////////////////////////////////////////////// |
670f9935 | 2 | // Name: src/common/http.cpp |
f4ada568 GL |
3 | // Purpose: HTTP protocol |
4 | // Author: Guilhem Lavaux | |
dbccd1c2 | 5 | // Modified by: Simo Virokannas (authentication, Dec 2005) |
f4ada568 | 6 | // Created: August 1997 |
f4ada568 | 7 | // Copyright: (c) 1997, 1998 Guilhem Lavaux |
65571936 | 8 | // Licence: wxWindows licence |
f4ada568 GL |
9 | ///////////////////////////////////////////////////////////////////////////// |
10 | ||
fcc6dddd JS |
11 | // For compilers that support precompilation, includes "wx.h". |
12 | #include "wx/wxprec.h" | |
13 | ||
14 | #ifdef __BORLANDC__ | |
670f9935 | 15 | #pragma hdrstop |
fcc6dddd JS |
16 | #endif |
17 | ||
a5d46b73 | 18 | #if wxUSE_PROTOCOL_HTTP |
ce4169a4 | 19 | |
f4ada568 GL |
20 | #include <stdio.h> |
21 | #include <stdlib.h> | |
a8d628fc DS |
22 | |
23 | #ifndef WX_PRECOMP | |
670f9935 WS |
24 | #include "wx/string.h" |
25 | #include "wx/app.h" | |
a8d628fc DS |
26 | #endif |
27 | ||
f4ada568 GL |
28 | #include "wx/tokenzr.h" |
29 | #include "wx/socket.h" | |
30 | #include "wx/protocol/protocol.h" | |
fae05df5 | 31 | #include "wx/url.h" |
f4ada568 GL |
32 | #include "wx/protocol/http.h" |
33 | #include "wx/sckstrm.h" | |
204abcd4 | 34 | #include "wx/thread.h" |
f4ada568 | 35 | |
730b772b FM |
36 | |
37 | // ---------------------------------------------------------------------------- | |
38 | // wxHTTP | |
39 | // ---------------------------------------------------------------------------- | |
40 | ||
f4ada568 | 41 | IMPLEMENT_DYNAMIC_CLASS(wxHTTP, wxProtocol) |
5d3e7b52 | 42 | IMPLEMENT_PROTOCOL(wxHTTP, wxT("http"), wxT("80"), true) |
f4ada568 | 43 | |
f4ada568 | 44 | wxHTTP::wxHTTP() |
df5168c4 | 45 | : wxProtocol() |
f4ada568 | 46 | { |
48f7ffbe WS |
47 | m_addr = NULL; |
48 | m_read = false; | |
49 | m_proxy_mode = false; | |
48f7ffbe | 50 | m_http_response = 0; |
f4ada568 | 51 | |
48f7ffbe | 52 | SetNotify(wxSOCKET_LOST_FLAG); |
f4ada568 GL |
53 | } |
54 | ||
55 | wxHTTP::~wxHTTP() | |
2fb203e6 VZ |
56 | { |
57 | ClearHeaders(); | |
58 | ||
59 | delete m_addr; | |
60 | } | |
61 | ||
62 | void wxHTTP::ClearHeaders() | |
f4ada568 | 63 | { |
730b772b | 64 | m_headers.clear(); |
f4ada568 GL |
65 | } |
66 | ||
906cb3f1 JS |
67 | void wxHTTP::ClearCookies() |
68 | { | |
69 | m_cookies.clear(); | |
70 | } | |
71 | ||
730b772b | 72 | wxString wxHTTP::GetContentType() const |
f4ada568 | 73 | { |
48f7ffbe | 74 | return GetHeader(wxT("Content-Type")); |
f4ada568 GL |
75 | } |
76 | ||
f61815af GL |
77 | void wxHTTP::SetProxyMode(bool on) |
78 | { | |
48f7ffbe | 79 | m_proxy_mode = on; |
f61815af GL |
80 | } |
81 | ||
bdcade0a | 82 | wxHTTP::wxHeaderIterator wxHTTP::FindHeader(const wxString& header) |
71414756 | 83 | { |
bdcade0a MB |
84 | wxHeaderIterator it = m_headers.begin(); |
85 | for ( wxHeaderIterator en = m_headers.end(); it != en; ++it ) | |
86 | { | |
86501081 | 87 | if ( header.CmpNoCase(it->first) == 0 ) |
bdcade0a MB |
88 | break; |
89 | } | |
71414756 | 90 | |
bdcade0a MB |
91 | return it; |
92 | } | |
93 | ||
94 | wxHTTP::wxHeaderConstIterator wxHTTP::FindHeader(const wxString& header) const | |
95 | { | |
96 | wxHeaderConstIterator it = m_headers.begin(); | |
97 | for ( wxHeaderConstIterator en = m_headers.end(); it != en; ++it ) | |
71414756 | 98 | { |
86501081 | 99 | if ( header.CmpNoCase(it->first) == 0 ) |
71414756 VZ |
100 | break; |
101 | } | |
102 | ||
103 | return it; | |
104 | } | |
105 | ||
906cb3f1 JS |
106 | wxHTTP::wxCookieIterator wxHTTP::FindCookie(const wxString& cookie) |
107 | { | |
108 | wxCookieIterator it = m_cookies.begin(); | |
109 | for ( wxCookieIterator en = m_cookies.end(); it != en; ++it ) | |
110 | { | |
111 | if ( cookie.CmpNoCase(it->first) == 0 ) | |
112 | break; | |
113 | } | |
114 | ||
115 | return it; | |
116 | } | |
117 | ||
118 | wxHTTP::wxCookieConstIterator wxHTTP::FindCookie(const wxString& cookie) const | |
119 | { | |
120 | wxCookieConstIterator it = m_cookies.begin(); | |
121 | for ( wxCookieConstIterator en = m_cookies.end(); it != en; ++it ) | |
122 | { | |
123 | if ( cookie.CmpNoCase(it->first) == 0 ) | |
124 | break; | |
125 | } | |
126 | ||
127 | return it; | |
128 | } | |
129 | ||
f4ada568 GL |
130 | void wxHTTP::SetHeader(const wxString& header, const wxString& h_data) |
131 | { | |
48f7ffbe WS |
132 | if (m_read) { |
133 | ClearHeaders(); | |
134 | m_read = false; | |
135 | } | |
f4ada568 | 136 | |
48f7ffbe WS |
137 | wxHeaderIterator it = FindHeader(header); |
138 | if (it != m_headers.end()) | |
139 | it->second = h_data; | |
140 | else | |
141 | m_headers[header] = h_data; | |
f4ada568 GL |
142 | } |
143 | ||
71414756 | 144 | wxString wxHTTP::GetHeader(const wxString& header) const |
f4ada568 | 145 | { |
bdcade0a | 146 | wxHeaderConstIterator it = FindHeader(header); |
f4ada568 | 147 | |
01482482 | 148 | return it == m_headers.end() ? wxGetEmptyString() : it->second; |
f4ada568 GL |
149 | } |
150 | ||
906cb3f1 JS |
151 | wxString wxHTTP::GetCookie(const wxString& cookie) const |
152 | { | |
153 | wxCookieConstIterator it = FindCookie(cookie); | |
154 | ||
155 | return it == m_cookies.end() ? wxGetEmptyString() : it->second; | |
156 | } | |
157 | ||
dbccd1c2 JS |
158 | wxString wxHTTP::GenerateAuthString(const wxString& user, const wxString& pass) const |
159 | { | |
e97cbf83 VZ |
160 | // TODO: Use wxBase64Encode() now that we have it instead of reproducing it |
161 | ||
dbccd1c2 JS |
162 | static const char *base64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; |
163 | ||
164 | wxString buf; | |
165 | wxString toencode; | |
166 | ||
167 | buf.Printf(wxT("Basic ")); | |
168 | ||
169 | toencode.Printf(wxT("%s:%s"),user.c_str(),pass.c_str()); | |
170 | ||
670f9935 | 171 | size_t len = toencode.length(); |
dbccd1c2 JS |
172 | const wxChar *from = toencode.c_str(); |
173 | while (len >= 3) { // encode full blocks first | |
174 | buf << wxString::Format(wxT("%c%c"), base64[(from[0] >> 2) & 0x3f], base64[((from[0] << 4) & 0x30) | ((from[1] >> 4) & 0xf)]); | |
175 | buf << wxString::Format(wxT("%c%c"), base64[((from[1] << 2) & 0x3c) | ((from[2] >> 6) & 0x3)], base64[from[2] & 0x3f]); | |
176 | from += 3; | |
177 | len -= 3; | |
178 | } | |
179 | if (len > 0) { // pad the remaining characters | |
180 | buf << wxString::Format(wxT("%c"), base64[(from[0] >> 2) & 0x3f]); | |
181 | if (len == 1) { | |
182 | buf << wxString::Format(wxT("%c="), base64[(from[0] << 4) & 0x30]); | |
183 | } else { | |
886f61ca | 184 | buf << wxString::Format(wxT("%c%c"), base64[((from[0] << 4) & 0x30) | ((from[1] >> 4) & 0xf)], base64[(from[1] << 2) & 0x3c]); |
dbccd1c2 | 185 | } |
2523e9b7 | 186 | buf << wxT("="); |
dbccd1c2 JS |
187 | } |
188 | ||
189 | return buf; | |
190 | } | |
191 | ||
f9133b32 VZ |
192 | void wxHTTP::SetPostBuffer(const wxString& post_buf) |
193 | { | |
ab9d6a4c VZ |
194 | // Use To8BitData() for backwards compatibility in this deprecated method. |
195 | // The new code should use the other overload or SetPostText() and specify | |
196 | // the encoding to use for the text explicitly. | |
197 | wxScopedCharBuffer scb = post_buf.To8BitData(); | |
198 | if ( scb.length() ) | |
199 | { | |
200 | m_postBuffer.Clear(); | |
201 | m_postBuffer.AppendData(scb.data(), scb.length()); | |
202 | } | |
203 | } | |
204 | ||
205 | bool | |
206 | wxHTTP::SetPostBuffer(const wxString& contentType, | |
207 | const wxMemoryBuffer& data) | |
208 | { | |
209 | m_postBuffer = data; | |
210 | m_contentType = contentType; | |
211 | ||
212 | return !m_postBuffer.IsEmpty(); | |
213 | } | |
214 | ||
215 | bool | |
216 | wxHTTP::SetPostText(const wxString& contentType, | |
217 | const wxString& data, | |
218 | const wxMBConv& conv) | |
219 | { | |
c84ef5b9 | 220 | #if wxUSE_UNICODE |
ab9d6a4c | 221 | wxScopedCharBuffer scb = data.mb_str(conv); |
c84ef5b9 VZ |
222 | const size_t len = scb.length(); |
223 | const char* const buf = scb.data(); | |
224 | #else // !wxUSE_UNICODE | |
225 | const size_t len = data.length(); | |
226 | const char* const buf = data.mb_str(conv); | |
227 | #endif // wxUSE_UNICODE/!wxUSE_UNICODE | |
228 | ||
229 | if ( !len ) | |
ab9d6a4c VZ |
230 | return false; |
231 | ||
232 | m_postBuffer.Clear(); | |
c84ef5b9 | 233 | m_postBuffer.AppendData(buf, len); |
ab9d6a4c VZ |
234 | m_contentType = contentType; |
235 | ||
236 | return true; | |
f9133b32 VZ |
237 | } |
238 | ||
f4ada568 GL |
239 | void wxHTTP::SendHeaders() |
240 | { | |
48f7ffbe WS |
241 | typedef wxStringToStringHashMap::iterator iterator; |
242 | wxString buf; | |
f4ada568 | 243 | |
48f7ffbe WS |
244 | for (iterator it = m_headers.begin(), en = m_headers.end(); it != en; ++it ) |
245 | { | |
246 | buf.Printf(wxT("%s: %s\r\n"), it->first.c_str(), it->second.c_str()); | |
53c6e7cc | 247 | |
48f7ffbe WS |
248 | const wxWX2MBbuf cbuf = buf.mb_str(); |
249 | Write(cbuf, strlen(cbuf)); | |
250 | } | |
f4ada568 GL |
251 | } |
252 | ||
253 | bool wxHTTP::ParseHeaders() | |
254 | { | |
48f7ffbe WS |
255 | wxString line; |
256 | wxStringTokenizer tokenzr; | |
f4ada568 | 257 | |
48f7ffbe | 258 | ClearHeaders(); |
906cb3f1 | 259 | ClearCookies(); |
48f7ffbe | 260 | m_read = true; |
f4ada568 | 261 | |
a09f8377 | 262 | for ( ;; ) |
48f7ffbe | 263 | { |
730b772b FM |
264 | m_lastError = ReadLine(this, line); |
265 | if (m_lastError != wxPROTO_NOERR) | |
48f7ffbe WS |
266 | return false; |
267 | ||
6636ef8d | 268 | if ( line.empty() ) |
48f7ffbe WS |
269 | break; |
270 | ||
271 | wxString left_str = line.BeforeFirst(':'); | |
906cb3f1 JS |
272 | if(!left_str.CmpNoCase("Set-Cookie")) |
273 | { | |
274 | wxString cookieName = line.AfterFirst(':').Strip(wxString::both).BeforeFirst('='); | |
275 | wxString cookieValue = line.AfterFirst(':').Strip(wxString::both).AfterFirst('=').BeforeFirst(';'); | |
276 | m_cookies[cookieName] = cookieValue; | |
277 | ||
278 | // For compatibility | |
279 | m_headers[left_str] = line.AfterFirst(':').Strip(wxString::both); | |
280 | } | |
281 | else | |
282 | { | |
283 | m_headers[left_str] = line.AfterFirst(':').Strip(wxString::both); | |
284 | } | |
48f7ffbe WS |
285 | } |
286 | return true; | |
f4ada568 GL |
287 | } |
288 | ||
f9133b32 | 289 | bool wxHTTP::Connect(const wxString& host, unsigned short port) |
f4ada568 | 290 | { |
48f7ffbe | 291 | wxIPV4address *addr; |
f4ada568 | 292 | |
48f7ffbe | 293 | if (m_addr) { |
5276b0a5 | 294 | wxDELETE(m_addr); |
48f7ffbe WS |
295 | Close(); |
296 | } | |
f4ada568 | 297 | |
48f7ffbe | 298 | m_addr = addr = new wxIPV4address(); |
f4ada568 | 299 | |
48f7ffbe | 300 | if (!addr->Hostname(host)) { |
5276b0a5 | 301 | wxDELETE(m_addr); |
730b772b | 302 | m_lastError = wxPROTO_NETERR; |
48f7ffbe WS |
303 | return false; |
304 | } | |
f4ada568 | 305 | |
48f7ffbe WS |
306 | if ( port ) |
307 | addr->Service(port); | |
308 | else if (!addr->Service(wxT("http"))) | |
309 | addr->Service(80); | |
ce22d615 | 310 | |
1c7a6772 VZ |
311 | wxString hostHdr = host; |
312 | if ( port && port != 80 ) | |
313 | hostHdr << wxT(":") << port; | |
314 | SetHeader(wxT("Host"), hostHdr); | |
f4ada568 | 315 | |
730b772b | 316 | m_lastError = wxPROTO_NOERR; |
48f7ffbe | 317 | return true; |
f4ada568 GL |
318 | } |
319 | ||
ddc7f0c9 | 320 | bool wxHTTP::Connect(const wxSockAddress& addr, bool WXUNUSED(wait)) |
f4ada568 | 321 | { |
48f7ffbe WS |
322 | if (m_addr) { |
323 | delete m_addr; | |
324 | Close(); | |
325 | } | |
f4ada568 | 326 | |
48f7ffbe | 327 | m_addr = addr.Clone(); |
acd15a3f | 328 | |
48f7ffbe | 329 | wxIPV4address *ipv4addr = wxDynamicCast(&addr, wxIPV4address); |
1c7a6772 VZ |
330 | if ( ipv4addr ) |
331 | { | |
332 | wxString hostHdr = ipv4addr->OrigHostname(); | |
333 | unsigned short port = ipv4addr->Service(); | |
334 | if ( port && port != 80 ) | |
335 | hostHdr << wxT(":") << port; | |
336 | SetHeader(wxT("Host"), hostHdr); | |
337 | } | |
5b96a71a | 338 | |
730b772b | 339 | m_lastError = wxPROTO_NOERR; |
48f7ffbe | 340 | return true; |
f4ada568 GL |
341 | } |
342 | ||
6535170f | 343 | bool wxHTTP::BuildRequest(const wxString& path, const wxString& method) |
f4ada568 | 344 | { |
6535170f VZ |
345 | // Use the data in the post buffer, if any. |
346 | if ( !m_postBuffer.IsEmpty() ) | |
48f7ffbe | 347 | { |
6535170f VZ |
348 | wxString len; |
349 | len << m_postBuffer.GetDataLen(); | |
350 | ||
351 | // Content length must be correct, so always set, possibly | |
352 | // overriding the value set explicitly by a previous call to | |
353 | // SetHeader("Content-Length"). | |
354 | SetHeader(wxS("Content-Length"), len); | |
355 | ||
356 | // However if the user had explicitly set the content type, don't | |
357 | // override it with the content type passed to SetPostText(). | |
358 | if ( !m_contentType.empty() && GetContentType().empty() ) | |
359 | SetHeader(wxS("Content-Type"), m_contentType); | |
48f7ffbe WS |
360 | } |
361 | ||
362 | m_http_response = 0; | |
363 | ||
364 | // If there is no User-Agent defined, define it. | |
6636ef8d | 365 | if ( GetHeader(wxT("User-Agent")).empty() ) |
48f7ffbe WS |
366 | SetHeader(wxT("User-Agent"), wxT("wxWidgets 2.x")); |
367 | ||
dbccd1c2 | 368 | // Send authentication information |
670f9935 | 369 | if (!m_username.empty() || !m_password.empty()) { |
dbccd1c2 JS |
370 | SetHeader(wxT("Authorization"), GenerateAuthString(m_username, m_password)); |
371 | } | |
372 | ||
48f7ffbe WS |
373 | SaveState(); |
374 | ||
375 | // we may use non blocking sockets only if we can dispatch events from them | |
d15e514e VZ |
376 | int flags = wxIsMainThread() && wxApp::IsMainLoopRunning() ? wxSOCKET_NONE |
377 | : wxSOCKET_BLOCK; | |
378 | // and we must use wxSOCKET_WAITALL to ensure that all data is sent | |
379 | flags |= wxSOCKET_WAITALL; | |
380 | SetFlags(flags); | |
48f7ffbe WS |
381 | Notify(false); |
382 | ||
383 | wxString buf; | |
6535170f | 384 | buf.Printf(wxT("%s %s HTTP/1.0\r\n"), method, path); |
86501081 VS |
385 | const wxWX2MBbuf pathbuf = buf.mb_str(); |
386 | Write(pathbuf, strlen(pathbuf)); | |
48f7ffbe WS |
387 | SendHeaders(); |
388 | Write("\r\n", 2); | |
389 | ||
6535170f VZ |
390 | if ( !m_postBuffer.IsEmpty() ) { |
391 | Write(m_postBuffer.GetData(), m_postBuffer.GetDataLen()); | |
ab9d6a4c VZ |
392 | |
393 | m_postBuffer.Clear(); | |
48f7ffbe WS |
394 | } |
395 | ||
396 | wxString tmp_str; | |
730b772b FM |
397 | m_lastError = ReadLine(this, tmp_str); |
398 | if (m_lastError != wxPROTO_NOERR) { | |
48f7ffbe WS |
399 | RestoreState(); |
400 | return false; | |
401 | } | |
402 | ||
403 | if (!tmp_str.Contains(wxT("HTTP/"))) { | |
404 | // TODO: support HTTP v0.9 which can have no header. | |
405 | // FIXME: tmp_str is not put back in the in-queue of the socket. | |
730b772b | 406 | m_lastError = wxPROTO_NOERR; |
48f7ffbe WS |
407 | SetHeader(wxT("Content-Length"), wxT("-1")); |
408 | SetHeader(wxT("Content-Type"), wxT("none/none")); | |
409 | RestoreState(); | |
410 | return true; | |
411 | } | |
f4ada568 | 412 | |
48f7ffbe WS |
413 | wxStringTokenizer token(tmp_str,wxT(' ')); |
414 | wxString tmp_str2; | |
415 | bool ret_value; | |
416 | ||
417 | token.NextToken(); | |
418 | tmp_str2 = token.NextToken(); | |
419 | ||
420 | m_http_response = wxAtoi(tmp_str2); | |
421 | ||
c9f78968 | 422 | switch ( tmp_str2[0u].GetValue() ) |
48f7ffbe WS |
423 | { |
424 | case wxT('1'): | |
425 | /* INFORMATION / SUCCESS */ | |
426 | break; | |
427 | ||
428 | case wxT('2'): | |
429 | /* SUCCESS */ | |
430 | break; | |
431 | ||
432 | case wxT('3'): | |
433 | /* REDIRECTION */ | |
434 | break; | |
435 | ||
436 | default: | |
730b772b | 437 | m_lastError = wxPROTO_NOFILE; |
48f7ffbe WS |
438 | RestoreState(); |
439 | return false; | |
440 | } | |
441 | ||
730b772b | 442 | m_lastError = wxPROTO_NOERR; |
48f7ffbe WS |
443 | ret_value = ParseHeaders(); |
444 | RestoreState(); | |
445 | return ret_value; | |
f4ada568 GL |
446 | } |
447 | ||
730b772b FM |
448 | bool wxHTTP::Abort(void) |
449 | { | |
450 | return wxSocketClient::Close(); | |
451 | } | |
452 | ||
453 | // ---------------------------------------------------------------------------- | |
454 | // wxHTTPStream and wxHTTP::GetInputStream | |
455 | // ---------------------------------------------------------------------------- | |
456 | ||
fc4b32c2 GRG |
457 | class wxHTTPStream : public wxSocketInputStream |
458 | { | |
f4ada568 | 459 | public: |
48f7ffbe WS |
460 | wxHTTP *m_http; |
461 | size_t m_httpsize; | |
462 | unsigned long m_read_bytes; | |
9a1b2c28 | 463 | |
f6687493 VZ |
464 | wxHTTPStream(wxHTTP *http) : wxSocketInputStream(*http) |
465 | { | |
466 | m_http = http; | |
467 | m_httpsize = 0; | |
468 | m_read_bytes = 0; | |
469 | } | |
470 | ||
48f7ffbe WS |
471 | size_t GetSize() const { return m_httpsize; } |
472 | virtual ~wxHTTPStream(void) { m_http->Abort(); } | |
a324a7bc GL |
473 | |
474 | protected: | |
48f7ffbe | 475 | size_t OnSysRead(void *buffer, size_t bufsize); |
22f3361e | 476 | |
c0c133e1 | 477 | wxDECLARE_NO_COPY_CLASS(wxHTTPStream); |
f4ada568 GL |
478 | }; |
479 | ||
a324a7bc GL |
480 | size_t wxHTTPStream::OnSysRead(void *buffer, size_t bufsize) |
481 | { | |
ccc3a25d | 482 | if (m_read_bytes >= m_httpsize) |
32013d27 VZ |
483 | { |
484 | m_lasterror = wxSTREAM_EOF; | |
485 | return 0; | |
486 | } | |
a324a7bc | 487 | |
32013d27 VZ |
488 | size_t ret = wxSocketInputStream::OnSysRead(buffer, bufsize); |
489 | m_read_bytes += ret; | |
a324a7bc | 490 | |
8b6b8e21 SC |
491 | if (m_httpsize==(size_t)-1 && m_lasterror == wxSTREAM_READ_ERROR ) |
492 | { | |
493 | // if m_httpsize is (size_t) -1 this means read until connection closed | |
494 | // which is equivalent to getting a READ_ERROR, for clients however this | |
495 | // must be translated into EOF, as it is the expected way of signalling | |
496 | // end end of the content | |
730b772b | 497 | m_lasterror = wxSTREAM_EOF; |
8b6b8e21 SC |
498 | } |
499 | ||
32013d27 | 500 | return ret; |
a324a7bc GL |
501 | } |
502 | ||
f4ada568 GL |
503 | wxInputStream *wxHTTP::GetInputStream(const wxString& path) |
504 | { | |
48f7ffbe | 505 | wxHTTPStream *inp_stream; |
8f5bda17 | 506 | |
48f7ffbe | 507 | wxString new_path; |
f4ada568 | 508 | |
730b772b | 509 | m_lastError = wxPROTO_CONNERR; // all following returns share this type of error |
48f7ffbe WS |
510 | if (!m_addr) |
511 | return NULL; | |
f4ada568 | 512 | |
48f7ffbe | 513 | // We set m_connected back to false so wxSocketBase will know what to do. |
ad8b8498 | 514 | #ifdef __WXMAC__ |
48f7ffbe WS |
515 | wxSocketClient::Connect(*m_addr , false ); |
516 | wxSocketClient::WaitOnConnect(10); | |
ad8b8498 SC |
517 | |
518 | if (!wxSocketClient::IsConnected()) | |
519 | return NULL; | |
520 | #else | |
48f7ffbe WS |
521 | if (!wxProtocol::Connect(*m_addr)) |
522 | return NULL; | |
ad8b8498 | 523 | #endif |
f4ada568 | 524 | |
6535170f VZ |
525 | // Use the user-specified method if any or determine the method to use |
526 | // automatically depending on whether we have anything to post or not. | |
527 | wxString method = m_method; | |
528 | if (method.empty()) | |
529 | method = m_postBuffer.IsEmpty() ? wxS("GET"): wxS("POST"); | |
530 | ||
531 | if (!BuildRequest(path, method)) | |
48f7ffbe | 532 | return NULL; |
f4ada568 | 533 | |
48f7ffbe | 534 | inp_stream = new wxHTTPStream(this); |
8f5bda17 | 535 | |
48f7ffbe | 536 | if (!GetHeader(wxT("Content-Length")).empty()) |
86501081 | 537 | inp_stream->m_httpsize = wxAtoi(GetHeader(wxT("Content-Length"))); |
48f7ffbe WS |
538 | else |
539 | inp_stream->m_httpsize = (size_t)-1; | |
a324a7bc | 540 | |
48f7ffbe | 541 | inp_stream->m_read_bytes = 0; |
a324a7bc | 542 | |
48f7ffbe WS |
543 | Notify(false); |
544 | SetFlags(wxSOCKET_BLOCK | wxSOCKET_WAITALL); | |
9a1b2c28 | 545 | |
730b772b FM |
546 | // no error; reset m_lastError |
547 | m_lastError = wxPROTO_NOERR; | |
48f7ffbe | 548 | return inp_stream; |
f4ada568 | 549 | } |
35a4dab7 | 550 | |
a5d46b73 | 551 | #endif // wxUSE_PROTOCOL_HTTP |