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