Fix a very annoying autorelease pool memory leak.
[wxWidgets.git] / src / msw / urlmsw.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/msw/urlmsw.cpp
3 // Purpose: MS-Windows native URL support based on WinINet
4 // Author: Hajo Kirchhoff
5 // Modified by:
6 // Created: 06/11/2003
7 // Copyright: (c) 2003 Hajo Kirchhoff
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
10
11 // For compilers that support precompilation, includes "wx.h".
12 #include "wx/wxprec.h"
13
14 #ifdef __BORLANDC__
15 #pragma hdrstop
16 #endif
17
18 #if wxUSE_URL_NATIVE
19
20 #ifndef WX_PRECOMP
21 #include "wx/list.h"
22 #include "wx/string.h"
23 #include "wx/utils.h"
24 #include "wx/module.h"
25 #include "wx/log.h"
26 #endif
27
28 #if !wxUSE_PROTOCOL_HTTP
29 #include "wx/protocol/protocol.h"
30
31 // empty http protocol replacement (for now)
32 // so that wxUSE_URL_NATIVE can be used with
33 // wxSOCKETS==0 and wxUSE_PROTOCOL_HTTP==0
34 class wxHTTPDummyProto : public wxProtocol
35 {
36 public:
37 wxHTTPDummyProto() : wxProtocol() { }
38
39 wxProtocolError GetError() { return m_error; }
40
41 virtual bool Abort() { return true; }
42
43 wxInputStream *GetInputStream(const wxString& WXUNUSED(path))
44 {
45 return 0; // input stream is returned by wxURLNativeImp
46 }
47
48 protected:
49 wxProtocolError m_error;
50
51 DECLARE_DYNAMIC_CLASS_NO_COPY(wxHTTPDummyProto)
52 DECLARE_PROTOCOL(wxHTTPDummyProto)
53 };
54
55 // the only "reason for being" for this class is to tell
56 // wxURL that there is someone dealing with the http protocol
57 IMPLEMENT_DYNAMIC_CLASS(wxHTTPDummyProto, wxProtocol)
58 IMPLEMENT_PROTOCOL(wxHTTPDummyProto, wxT("http"), NULL, false)
59 USE_PROTOCOL(wxHTTPDummyProto)
60
61 #endif // !wxUSE_PROTOCOL_HTTP
62
63
64 #ifdef __VISUALC__ // be conservative about this pragma
65 // tell the linker to include wininet.lib automatically
66 #pragma comment(lib, "wininet.lib")
67 #endif
68
69 #include "wx/url.h"
70
71 #include <string.h>
72 #include <ctype.h>
73 #include <wininet.h>
74
75 // this class needn't be exported
76 class wxWinINetURL:public wxURLNativeImp
77 {
78 public:
79 wxInputStream *GetInputStream(wxURL *owner);
80
81 protected:
82 // return the WinINet session handle
83 static HINTERNET GetSessionHandle();
84 };
85
86 HINTERNET wxWinINetURL::GetSessionHandle()
87 {
88 // this struct ensures that the session is opened when the
89 // first call to GetSessionHandle is made
90 // it also ensures that the session is closed when the program
91 // terminates
92 static struct INetSession
93 {
94 INetSession()
95 {
96 DWORD rc = InternetAttemptConnect(0);
97
98 m_handle = InternetOpen
99 (
100 wxVERSION_STRING,
101 INTERNET_OPEN_TYPE_PRECONFIG,
102 NULL,
103 NULL,
104 rc == ERROR_SUCCESS ? 0 : INTERNET_FLAG_OFFLINE
105 );
106 }
107
108 ~INetSession()
109 {
110 InternetCloseHandle(m_handle);
111 }
112
113 HINTERNET m_handle;
114 } session;
115
116 return session.m_handle;
117 }
118
119 // this class needn't be exported
120 class /*WXDLLIMPEXP_NET */ wxWinINetInputStream : public wxInputStream
121 {
122 public:
123 wxWinINetInputStream(HINTERNET hFile=0);
124 virtual ~wxWinINetInputStream();
125
126 void Attach(HINTERNET hFile);
127
128 wxFileOffset SeekI( wxFileOffset WXUNUSED(pos), wxSeekMode WXUNUSED(mode) )
129 { return -1; }
130 wxFileOffset TellI() const
131 { return -1; }
132 size_t GetSize() const;
133
134 protected:
135 void SetError(wxStreamError err) { m_lasterror=err; }
136 HINTERNET m_hFile;
137 size_t OnSysRead(void *buffer, size_t bufsize);
138
139 wxDECLARE_NO_COPY_CLASS(wxWinINetInputStream);
140 };
141
142 size_t wxWinINetInputStream::GetSize() const
143 {
144 DWORD contentLength = 0;
145 DWORD dwSize = sizeof(contentLength);
146 DWORD index = 0;
147
148 if ( HttpQueryInfo( m_hFile, HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER, &contentLength, &dwSize, &index) )
149 return contentLength;
150 else
151 return 0;
152 }
153
154 size_t wxWinINetInputStream::OnSysRead(void *buffer, size_t bufsize)
155 {
156 DWORD bytesread = 0;
157 if ( !InternetReadFile(m_hFile, buffer, bufsize, &bytesread) )
158 {
159 DWORD lError = ::GetLastError();
160 if ( lError != ERROR_SUCCESS )
161 SetError(wxSTREAM_READ_ERROR);
162
163 DWORD iError, bLength;
164 InternetGetLastResponseInfo(&iError, NULL, &bLength);
165 if ( bLength > 0 )
166 {
167 wxString errorString;
168 InternetGetLastResponseInfo
169 (
170 &iError,
171 wxStringBuffer(errorString, bLength),
172 &bLength
173 );
174
175 wxLogError(wxT("Read failed with error %d: %s"),
176 iError, errorString);
177 }
178 }
179
180 if ( bytesread == 0 )
181 {
182 SetError(wxSTREAM_EOF);
183 }
184
185 return bytesread;
186 }
187
188 wxWinINetInputStream::wxWinINetInputStream(HINTERNET hFile)
189 : m_hFile(hFile)
190 {
191 }
192
193 void wxWinINetInputStream::Attach(HINTERNET newHFile)
194 {
195 wxCHECK_RET(m_hFile==NULL,
196 wxT("cannot attach new stream when stream already exists"));
197 m_hFile=newHFile;
198 SetError(m_hFile!=NULL ? wxSTREAM_NO_ERROR : wxSTREAM_READ_ERROR);
199 }
200
201 wxWinINetInputStream::~wxWinINetInputStream()
202 {
203 if ( m_hFile )
204 {
205 InternetCloseHandle(m_hFile);
206 m_hFile=0;
207 }
208 }
209
210 wxURLNativeImp *wxURL::CreateNativeImpObject()
211 {
212 return new wxWinINetURL;
213 }
214
215 wxInputStream *wxWinINetURL::GetInputStream(wxURL *owner)
216 {
217 DWORD service;
218 if ( owner->GetScheme() == wxT("http") )
219 {
220 service = INTERNET_SERVICE_HTTP;
221 }
222 else if ( owner->GetScheme() == wxT("ftp") )
223 {
224 service = INTERNET_SERVICE_FTP;
225 }
226 else
227 {
228 // unknown protocol. Let wxURL try another method.
229 return 0;
230 }
231
232 wxWinINetInputStream *newStream = new wxWinINetInputStream;
233 HINTERNET newStreamHandle = InternetOpenUrl
234 (
235 GetSessionHandle(),
236 owner->GetURL(),
237 NULL,
238 0,
239 INTERNET_FLAG_KEEP_CONNECTION |
240 INTERNET_FLAG_PASSIVE,
241 (DWORD_PTR)newStream
242 );
243 newStream->Attach(newStreamHandle);
244
245 return newStream;
246 }
247
248 #endif // wxUSE_URL_NATIVE