]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/common/http.cpp
added (and documented) msw.xp-tab-ok option
[wxWidgets.git] / src / common / http.cpp
... / ...
CommitLineData
1/////////////////////////////////////////////////////////////////////////////
2// Name: http.cpp
3// Purpose: HTTP protocol
4// Author: Guilhem Lavaux
5// Modified by:
6// Created: August 1997
7// RCS-ID: $Id$
8// Copyright: (c) 1997, 1998 Guilhem Lavaux
9// Licence: wxWindows licence
10/////////////////////////////////////////////////////////////////////////////
11
12#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
13 #pragma implementation "http.h"
14#endif
15
16// For compilers that support precompilation, includes "wx.h".
17#include "wx/wxprec.h"
18
19#ifdef __BORLANDC__
20 #pragma hdrstop
21#endif
22
23#if wxUSE_PROTOCOL_HTTP
24
25#include <stdio.h>
26#include <stdlib.h>
27
28#ifndef WX_PRECOMP
29#include "wx/string.h"
30#include "wx/app.h"
31#endif
32
33#include "wx/tokenzr.h"
34#include "wx/socket.h"
35#include "wx/protocol/protocol.h"
36#include "wx/url.h"
37#include "wx/protocol/http.h"
38#include "wx/sckstrm.h"
39
40IMPLEMENT_DYNAMIC_CLASS(wxHTTP, wxProtocol)
41IMPLEMENT_PROTOCOL(wxHTTP, wxT("http"), wxT("80"), true)
42
43#define HTTP_BSIZE 2048
44
45wxHTTP::wxHTTP()
46 : wxProtocol()
47{
48 m_addr = NULL;
49 m_read = false;
50 m_proxy_mode = false;
51 m_post_buf = wxEmptyString;
52 m_http_response = 0;
53
54 SetNotify(wxSOCKET_LOST_FLAG);
55}
56
57wxHTTP::~wxHTTP()
58{
59 ClearHeaders();
60
61 delete m_addr;
62}
63
64void wxHTTP::ClearHeaders()
65{
66 m_headers.clear();
67}
68
69wxString wxHTTP::GetContentType()
70{
71 return GetHeader(wxT("Content-Type"));
72}
73
74void wxHTTP::SetProxyMode(bool on)
75{
76 m_proxy_mode = on;
77}
78
79wxHTTP::wxHeaderIterator wxHTTP::FindHeader(const wxString& header)
80{
81 wxHeaderIterator it = m_headers.begin();
82 for ( wxHeaderIterator en = m_headers.end(); it != en; ++it )
83 {
84 if ( wxStricmp(it->first, header) == 0 )
85 break;
86 }
87
88 return it;
89}
90
91wxHTTP::wxHeaderConstIterator wxHTTP::FindHeader(const wxString& header) const
92{
93 wxHeaderConstIterator it = m_headers.begin();
94 for ( wxHeaderConstIterator en = m_headers.end(); it != en; ++it )
95 {
96 if ( wxStricmp(it->first, header) == 0 )
97 break;
98 }
99
100 return it;
101}
102
103void wxHTTP::SetHeader(const wxString& header, const wxString& h_data)
104{
105 if (m_read) {
106 ClearHeaders();
107 m_read = false;
108 }
109
110 wxHeaderIterator it = FindHeader(header);
111 if (it != m_headers.end())
112 it->second = h_data;
113 else
114 m_headers[header] = h_data;
115}
116
117wxString wxHTTP::GetHeader(const wxString& header) const
118{
119 wxHeaderConstIterator it = FindHeader(header);
120
121 return it == m_headers.end() ? wxGetEmptyString() : it->second;
122}
123
124void wxHTTP::SetPostBuffer(const wxString& post_buf)
125{
126 m_post_buf = post_buf;
127}
128
129void wxHTTP::SendHeaders()
130{
131 typedef wxStringToStringHashMap::iterator iterator;
132 wxString buf;
133
134 for (iterator it = m_headers.begin(), en = m_headers.end(); it != en; ++it )
135 {
136 buf.Printf(wxT("%s: %s\r\n"), it->first.c_str(), it->second.c_str());
137
138 const wxWX2MBbuf cbuf = buf.mb_str();
139 Write(cbuf, strlen(cbuf));
140 }
141}
142
143bool wxHTTP::ParseHeaders()
144{
145 wxString line;
146 wxStringTokenizer tokenzr;
147
148 ClearHeaders();
149 m_read = true;
150
151#if defined(__VISAGECPP__)
152// VA just can't stand while(1)
153 bool bOs2var = true;
154 while(bOs2var)
155#else
156 while (1)
157#endif
158 {
159 m_perr = GetLine(this, line);
160 if (m_perr != wxPROTO_NOERR)
161 return false;
162
163 if (line.Length() == 0)
164 break;
165
166 wxString left_str = line.BeforeFirst(':');
167 m_headers[left_str] = line.AfterFirst(':').Strip(wxString::both);
168 }
169 return true;
170}
171
172bool wxHTTP::Connect(const wxString& host, unsigned short port)
173{
174 wxIPV4address *addr;
175
176 if (m_addr) {
177 delete m_addr;
178 m_addr = NULL;
179 Close();
180 }
181
182 m_addr = addr = new wxIPV4address();
183
184 if (!addr->Hostname(host)) {
185 delete m_addr;
186 m_addr = NULL;
187 m_perr = wxPROTO_NETERR;
188 return false;
189 }
190
191 if ( port ) addr->Service(port);
192 else if (!addr->Service(wxT("http")))
193 addr->Service(80);
194
195 SetHeader(wxT("Host"), host);
196
197 return true;
198}
199
200bool wxHTTP::Connect(wxSockAddress& addr, bool WXUNUSED(wait))
201{
202 if (m_addr) {
203 delete m_addr;
204 Close();
205 }
206
207 m_addr = addr.Clone();
208
209 wxIPV4address *ipv4addr = wxDynamicCast(&addr, wxIPV4address);
210 if (ipv4addr)
211 SetHeader(wxT("Host"), ipv4addr->OrigHostname());
212
213 return true;
214}
215
216bool wxHTTP::BuildRequest(const wxString& path, wxHTTP_Req req)
217{
218 const wxChar *request;
219
220 switch (req) {
221 case wxHTTP_GET:
222 request = wxT("GET");
223 break;
224 case wxHTTP_POST:
225 request = wxT("POST");
226 if ( GetHeader( wxT("Content-Length") ).IsNull() )
227 SetHeader( wxT("Content-Length"), wxString::Format( wxT("%lu"), (unsigned long)m_post_buf.Len() ) );
228 break;
229 default:
230 return false;
231 }
232
233 m_http_response = 0;
234
235 // If there is no User-Agent defined, define it.
236 if (GetHeader(wxT("User-Agent")).IsNull())
237 SetHeader(wxT("User-Agent"), wxT("wxWidgets 2.x"));
238
239 SaveState();
240
241 // we may use non blocking sockets only if we can dispatch events from them
242 SetFlags( wxIsMainThread() && wxApp::IsMainLoopRunning() ? wxSOCKET_NONE
243 : wxSOCKET_BLOCK );
244 Notify(false);
245
246 wxString buf;
247 buf.Printf(wxT("%s %s HTTP/1.0\r\n"), request, path.c_str());
248 const wxWX2MBbuf pathbuf = wxConvLocal.cWX2MB(buf);
249 Write(pathbuf, strlen(wxMBSTRINGCAST pathbuf));
250 SendHeaders();
251 Write("\r\n", 2);
252
253 if ( req == wxHTTP_POST ) {
254 Write(m_post_buf.mbc_str(), m_post_buf.Len());
255 m_post_buf = wxEmptyString;
256 }
257
258 wxString tmp_str;
259 m_perr = GetLine(this, tmp_str);
260 if (m_perr != wxPROTO_NOERR) {
261 RestoreState();
262 return false;
263 }
264
265 if (!tmp_str.Contains(wxT("HTTP/"))) {
266 // TODO: support HTTP v0.9 which can have no header.
267 // FIXME: tmp_str is not put back in the in-queue of the socket.
268 SetHeader(wxT("Content-Length"), wxT("-1"));
269 SetHeader(wxT("Content-Type"), wxT("none/none"));
270 RestoreState();
271 return true;
272 }
273
274 wxStringTokenizer token(tmp_str,wxT(' '));
275 wxString tmp_str2;
276 bool ret_value;
277
278 token.NextToken();
279 tmp_str2 = token.NextToken();
280
281 m_http_response = wxAtoi(tmp_str2);
282
283 switch (tmp_str2[0u]) {
284 case wxT('1'):
285 /* INFORMATION / SUCCESS */
286 break;
287 case wxT('2'):
288 /* SUCCESS */
289 break;
290 case wxT('3'):
291 /* REDIRECTION */
292 break;
293 default:
294 m_perr = wxPROTO_NOFILE;
295 RestoreState();
296 return false;
297 }
298
299 ret_value = ParseHeaders();
300 RestoreState();
301 return ret_value;
302}
303
304class wxHTTPStream : public wxSocketInputStream
305{
306public:
307 wxHTTP *m_http;
308 size_t m_httpsize;
309 unsigned long m_read_bytes;
310
311 wxHTTPStream(wxHTTP *http) : wxSocketInputStream(*http), m_http(http) {}
312 size_t GetSize() const { return m_httpsize; }
313 virtual ~wxHTTPStream(void) { m_http->Abort(); }
314
315protected:
316 size_t OnSysRead(void *buffer, size_t bufsize);
317
318 DECLARE_NO_COPY_CLASS(wxHTTPStream)
319};
320
321size_t wxHTTPStream::OnSysRead(void *buffer, size_t bufsize)
322{
323 if (m_httpsize > 0 && m_read_bytes >= m_httpsize)
324 {
325 m_lasterror = wxSTREAM_EOF;
326 return 0;
327 }
328
329 size_t ret = wxSocketInputStream::OnSysRead(buffer, bufsize);
330 m_read_bytes += ret;
331
332 return ret;
333}
334
335bool wxHTTP::Abort(void)
336{
337 return wxSocketClient::Close();
338}
339
340wxInputStream *wxHTTP::GetInputStream(const wxString& path)
341{
342 wxHTTPStream *inp_stream;
343
344 wxString new_path;
345
346 m_perr = wxPROTO_CONNERR;
347 if (!m_addr)
348 return NULL;
349
350 // We set m_connected back to false so wxSocketBase will know what to do.
351#ifdef __WXMAC__
352 wxSocketClient::Connect(*m_addr , false );
353 wxSocketClient::WaitOnConnect(10);
354
355 if (!wxSocketClient::IsConnected())
356 return NULL;
357#else
358 if (!wxProtocol::Connect(*m_addr))
359 return NULL;
360#endif
361
362 if (!BuildRequest(path, m_post_buf.IsEmpty() ? wxHTTP_GET : wxHTTP_POST))
363 return NULL;
364
365 inp_stream = new wxHTTPStream(this);
366
367 if (!GetHeader(wxT("Content-Length")).IsEmpty())
368 inp_stream->m_httpsize = wxAtoi(WXSTRINGCAST GetHeader(wxT("Content-Length")));
369 else
370 inp_stream->m_httpsize = (size_t)-1;
371
372 inp_stream->m_read_bytes = 0;
373
374 Notify(false);
375 SetFlags(wxSOCKET_BLOCK | wxSOCKET_WAITALL);
376
377 return inp_stream;
378}
379
380#endif // wxUSE_PROTOCOL_HTTP
381