From 25959b956d323264d8c974a41eea579bf565cd8e Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sat, 7 Feb 2004 15:28:06 +0000 Subject: [PATCH] wxURL implementation using WinInet functions under Win32 (patch 839305) git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@25562 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- build/bakefiles/files.bkl | 1 + docs/changes.txt | 2 + include/wx/msw/setup0.h | 10 ++ include/wx/url.h | 19 ++++ src/common/url.cpp | 25 +++- src/msw/urlmsw.cpp | 233 ++++++++++++++++++++++++++++++++++++++ 6 files changed, 287 insertions(+), 3 deletions(-) create mode 100644 src/msw/urlmsw.cpp diff --git a/build/bakefiles/files.bkl b/build/bakefiles/files.bkl index 00e8232608..b27840a1fd 100644 --- a/build/bakefiles/files.bkl +++ b/build/bakefiles/files.bkl @@ -309,6 +309,7 @@ IMPORTANT: please read docs/tech/tn0016.txt before modifying this file! src/msw/gsocket.c + src/msw/urlmsw.cpp wx/msw/gsockmsw.h diff --git a/docs/changes.txt b/docs/changes.txt index 93bda7d04d..c203cedc2d 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -34,6 +34,7 @@ INCOMPATIBLE CHANGES SINCE 2.4.x - wxTabView::GetLayers() changed return type from wxList& to wxTabLayerList& (when WXWIN_COMPATIBILITY_2_4 == 0) - wxID_SEPARATOR (id used for the menu separators) value changed from -1 to -2 +- wxGetNumberFromUser() is now in separate wx/numdlg.h, not wx/textdlg.h DEPRECATED METHODS SINCE 2.4.x @@ -146,6 +147,7 @@ wxMSW: wxEVT_COMMAND_COMBOBOX_SELECTED changed the selection - wxFileDialog now returns correct filter index for multiple-file dialogs - added wxTextCtrl::HitTest() +- experimental wxURL implementation using WinInet functions (Hajo Kirchhoff) wxGTK: diff --git a/include/wx/msw/setup0.h b/include/wx/msw/setup0.h index 1efd582ebe..c094148dd7 100644 --- a/include/wx/msw/setup0.h +++ b/include/wx/msw/setup0.h @@ -435,6 +435,16 @@ // Define this to use wxURL class. #define wxUSE_URL 1 +// Define this to use native platform url and protocol support. +// Currently valid only for MS-Windows. +// Note: if you set this to 1, you can open ftp/http/gopher sites +// and obtain a valid input stream for these sites +// even when you set wxUSE_PROTOCOL_FTP/HTTP to 0. +// Doing so reduces the code size. +// +// This code is experimental and subject to change. +#define wxUSE_URL_NATIVE 0 + // Support for regular expression matching via wxRegEx class: enable this to // use POSIX regular expressions in your code. You need to compile regex // library from src/regex to use it under Windows. diff --git a/include/wx/url.h b/include/wx/url.h index dc220b8a5f..59d8428060 100644 --- a/include/wx/url.h +++ b/include/wx/url.h @@ -37,6 +37,17 @@ typedef enum { wxURL_PROTOERR } wxURLError; +#if wxUSE_URL_NATIVE +class WXDLLIMPEXP_NET wxURL; + +class WXDLLIMPEXP_NET wxURLNativeImp : public wxObject +{ +public: + virtual ~wxURLNativeImp() { } + virtual wxInputStream *GetInputStream(wxURL *owner) = 0; +}; +#endif // wxUSE_URL_NATIVE + class WXDLLIMPEXP_NET wxURL : public wxObject { public: @@ -72,6 +83,14 @@ protected: wxHTTP *m_proxy; #endif // wxUSE_SOCKETS +#if wxUSE_URL_NATIVE + friend class wxURLNativeImp; + // pointer to a native URL implementation object + wxURLNativeImp *m_nativeImp; + // Creates on the heap and returns a native + // implementation object for the current platform. + static wxURLNativeImp *CreateNativeImpObject(); +#endif wxProtoInfo *m_protoinfo; wxProtocol *m_protocol; diff --git a/src/common/url.cpp b/src/common/url.cpp index e265e0c5f3..6c0da6ee29 100644 --- a/src/common/url.cpp +++ b/src/common/url.cpp @@ -61,6 +61,9 @@ wxURL::wxURL(const wxString& url) m_protocol = NULL; m_error = wxURL_NOERR; m_url = url; +#if wxUSE_URL_NATIVE + m_nativeImp = CreateNativeImpObject(); +#endif #if wxUSE_SOCKETS if ( ms_useDefaultProxy && !ms_proxyDefault ) @@ -157,10 +160,13 @@ void wxURL::CleanData() wxURL::~wxURL() { - CleanData(); + CleanData(); #if wxUSE_SOCKETS - if (m_proxy && m_proxy != ms_proxyDefault) - delete m_proxy; + if (m_proxy && m_proxy != ms_proxyDefault) + delete m_proxy; +#endif +#if wxUSE_URL_NATIVE + delete m_nativeImp; #endif } @@ -285,6 +291,19 @@ wxInputStream *wxURL::GetInputStream() m_protocol->SetPassword(m_password); } +#if wxUSE_URL_NATIVE + // give the native implementation to return a better stream + // such as the native WinINet functionality under MS-Windows + if (m_nativeImp) + { + wxInputStream *rc; + rc = m_nativeImp->GetInputStream(this); + if (rc != 0) + return rc; + } + // else use the standard behaviour +#endif // wxUSE_URL_NATIVE + #if wxUSE_SOCKETS wxIPV4address addr; diff --git a/src/msw/urlmsw.cpp b/src/msw/urlmsw.cpp new file mode 100644 index 0000000000..404da29892 --- /dev/null +++ b/src/msw/urlmsw.cpp @@ -0,0 +1,233 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: msw/urlmsw.cpp +// Purpose: MS-Windows native URL support based on WinINet +// Author: Hajo Kirchhoff +// Modified by: +// Created: 06/11/2003 +// RCS-ID: $Id$ +// Copyright: (c) 2003 Hajo Kirchhoff +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_URL_NATIVE + +#if !wxUSE_PROTOCOL_HTTP +#include + +// empty http protocol replacement (for now) +// so that wxUSE_URL_NATIVE can be used with +// wxSOCKETS==0 and wxUSE_PROTOCOL_HTTP==0 +class wxHTTPDummyProto : public wxProtocol +{ +public: + wxHTTPDummyProto() : wxProtocol() { } + + wxProtocolError GetError() { return m_error; } + + virtual bool Abort() { return TRUE; } + + wxInputStream *GetInputStream(const wxString& WXUNUSED(path)) + { + return 0; // input stream is returned by wxURLNativeImp + } + +protected: + wxProtocolError m_error; + + DECLARE_DYNAMIC_CLASS_NO_COPY(wxHTTPDummyProto) + DECLARE_PROTOCOL(wxHTTPDummyProto) +}; + +// the only "reason for being" for this class is to tell +// wxURL that there is someone dealing with the http protocol +IMPLEMENT_DYNAMIC_CLASS(wxHTTPDummyProto, wxProtocol) +IMPLEMENT_PROTOCOL(wxHTTPDummyProto, wxT("http"), NULL, FALSE) +USE_PROTOCOL(wxHTTPDummyProto) + +#endif // !wxUSE_PROTOCOL_HTTP + + +#ifdef __VISUALC__ // be conservative about this pragma + // tell the linker to include wininet.lib automatically + #pragma comment(lib, "wininet.lib") +#endif + +#include "wx/string.h" +#include "wx/list.h" +#include "wx/utils.h" +#include "wx/module.h" +#include "wx/url.h" + +#include +#include +#include + +// this class needn't be exported +class wxWinINetURL:public wxURLNativeImp +{ +public: + wxInputStream *GetInputStream(wxURL *owner); + +protected: + // return the WinINet session handle + static HINTERNET GetSessionHandle(); +}; + +HINTERNET wxWinINetURL::GetSessionHandle() +{ + // this struct ensures that the session is opened when the + // first call to GetSessionHandle is made + // it also ensures that the session is closed when the program + // terminates + static struct INetSession + { + INetSession() + { + DWORD rc = InternetAttemptConnect(0); + + m_handle = InternetOpen + ( + wxVERSION_STRING, + INTERNET_OPEN_TYPE_PRECONFIG, + NULL, + NULL, + rc == ERROR_SUCCESS ? 0 : INTERNET_FLAG_OFFLINE + ); + } + + ~INetSession() + { + InternetCloseHandle(m_handle); + } + + HINTERNET m_handle; + } session; + + return session.m_handle; +} + +// this class needn't be exported +class /*WXDLLIMPEXP_NET */ wxWinINetInputStream : public wxInputStream +{ +public: + wxWinINetInputStream(HINTERNET hFile=0); + ~wxWinINetInputStream(); + + void Attach(HINTERNET hFile); + + off_t SeekI( off_t WXUNUSED(pos), wxSeekMode WXUNUSED(mode) ) + { return -1; } + off_t TellI() const + { return -1; } + +protected: + void SetError(wxStreamError err) { m_lasterror=err; } + HINTERNET m_hFile; + size_t OnSysRead(void *buffer, size_t bufsize); + + DECLARE_NO_COPY_CLASS(wxWinINetInputStream) +}; + +size_t wxWinINetInputStream::OnSysRead(void *buffer, size_t bufsize) +{ + DWORD bytesread = 0; + if ( !InternetReadFile(m_hFile, buffer, bufsize, &bytesread) ) + { + DWORD lError = ::GetLastError(); + if ( lError != ERROR_SUCCESS ) + SetError(wxSTREAM_READ_ERROR); + + DWORD iError, bLength; + InternetGetLastResponseInfo(&iError, NULL, &bLength); + if ( bLength > 0 ) + { + wxString errorString; + InternetGetLastResponseInfo + ( + &iError, + wxStringBuffer(errorString, bLength), + &bLength + ); + + wxLogError(wxT("Read failed with error %d: %s"), + iError, errorString); + } + } + + if ( bytesread == 0 ) + { + SetError(wxSTREAM_EOF); + } + + return bytesread; +} + +wxWinINetInputStream::wxWinINetInputStream(HINTERNET hFile) + : m_hFile(hFile) +{ +} + +void wxWinINetInputStream::Attach(HINTERNET newHFile) +{ + wxCHECK_RET(m_hFile==NULL, + wxT("cannot attach new stream when stream already exists")); + m_hFile=newHFile; + SetError(m_hFile!=NULL ? wxSTREAM_NO_ERROR : wxSTREAM_READ_ERROR); +} + +wxWinINetInputStream::~wxWinINetInputStream() +{ + if ( m_hFile ) + { + InternetCloseHandle(m_hFile); + m_hFile=0; + } +} + +wxURLNativeImp *wxURL::CreateNativeImpObject() +{ + return new wxWinINetURL; +} + +wxInputStream *wxWinINetURL::GetInputStream(wxURL *owner) +{ + DWORD service; + if ( owner->GetProtocolName() == wxT("http") ) + { + service = INTERNET_SERVICE_HTTP; + } + else if ( owner->GetProtocolName() == wxT("ftp") ) + { + service = INTERNET_SERVICE_FTP; + } + else + { + // unknown protocol. Let wxURL try another method. + return 0; + } + + wxWinINetInputStream *newStream = new wxWinINetInputStream; + HINTERNET newStreamHandle = InternetOpenUrl + ( + GetSessionHandle(), + owner->GetURL(), + NULL, + 0, + INTERNET_FLAG_KEEP_CONNECTION | + INTERNET_FLAG_PASSIVE, + (DWORD_PTR)newStream + ); + newStream->Attach(newStreamHandle); + + return newStream; +} + +#endif // wxUSE_URL_NATIVE +