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