home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / wxos2240.zip / wxWindows-2.4.0 / src / common / url.cpp < prev    next >
C/C++ Source or Header  |  2002-11-04  |  12KB  |  529 lines

  1. /////////////////////////////////////////////////////////////////////////////
  2. // Name:        url.cpp
  3. // Purpose:     URL parser
  4. // Author:      Guilhem Lavaux
  5. // Modified by:
  6. // Created:     20/07/1997
  7. // RCS-ID:      $Id: url.cpp,v 1.31.2.1 2002/11/03 15:48:13 RR Exp $
  8. // Copyright:   (c) 1997, 1998 Guilhem Lavaux
  9. // Licence:     wxWindows license
  10. /////////////////////////////////////////////////////////////////////////////
  11.  
  12. #ifdef __GNUG__
  13. #pragma implementation "url.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_URL
  24.  
  25. #include "wx/string.h"
  26. #include "wx/list.h"
  27. #include "wx/utils.h"
  28. #include "wx/module.h"
  29. #include "wx/url.h"
  30.  
  31. #include <string.h>
  32. #include <ctype.h>
  33.  
  34. IMPLEMENT_CLASS(wxProtoInfo, wxObject)
  35. IMPLEMENT_CLASS(wxURL, wxObject)
  36.  
  37. // Protocols list
  38. wxProtoInfo *wxURL::ms_protocols = NULL;
  39.  
  40. // Enforce linking of protocol classes:
  41. USE_PROTOCOL(wxFileProto)
  42.  
  43. #if wxUSE_SOCKETS
  44. USE_PROTOCOL(wxHTTP)
  45. USE_PROTOCOL(wxFTP)
  46.  
  47.     wxHTTP *wxURL::ms_proxyDefault = NULL;
  48.     bool wxURL::ms_useDefaultProxy = FALSE;
  49. #endif
  50.  
  51. // --------------------------------------------------------------
  52. // wxURL
  53. // --------------------------------------------------------------
  54.  
  55. // --------------------------------------------------------------
  56. // --------- wxURL CONSTRUCTOR DESTRUCTOR -----------------------
  57. // --------------------------------------------------------------
  58.  
  59. wxURL::wxURL(const wxString& url)
  60. {
  61.     m_protocol = NULL;
  62.     m_error = wxURL_NOERR;
  63.     m_url = url;
  64.  
  65. #if wxUSE_SOCKETS
  66.     if ( ms_useDefaultProxy && !ms_proxyDefault )
  67.     {
  68.         SetDefaultProxy( wxGetenv(wxT("HTTP_PROXY")) );
  69.  
  70.         if ( !ms_proxyDefault )
  71.         {
  72.             // don't try again
  73.             ms_useDefaultProxy = FALSE;
  74.         }
  75.     }
  76.  
  77.     m_useProxy = ms_proxyDefault != NULL;
  78.     m_proxy = ms_proxyDefault;
  79. #endif // wxUSE_SOCKETS
  80.  
  81.     ParseURL();
  82. }
  83.  
  84. bool wxURL::ParseURL()
  85. {
  86.   wxString last_url = m_url;
  87.  
  88.   // If the URL was already parsed (m_protocol != NULL), pass this section.
  89.   if (!m_protocol)
  90.   {
  91.     // Clean up
  92.     CleanData();
  93.  
  94.     // Extract protocol name
  95.     if (!PrepProto(last_url))
  96.     {
  97.       m_error = wxURL_SNTXERR;
  98.       return FALSE;
  99.     }
  100.  
  101.     // Find and create the protocol object
  102.     if (!FetchProtocol())
  103.     {
  104.       m_error = wxURL_NOPROTO;
  105.       return FALSE;
  106.     }
  107.  
  108.     // Do we need a host name ?
  109.     if (m_protoinfo->m_needhost)
  110.     {
  111.       // Extract it
  112.       if (!PrepHost(last_url))
  113.       {
  114.         m_error = wxURL_SNTXERR;
  115.         return FALSE;
  116.       }
  117.     }
  118.  
  119.     // Extract full path
  120.     if (!PrepPath(last_url))
  121.     {
  122.       m_error = wxURL_NOPATH;
  123.       return FALSE;
  124.     }
  125.   }
  126.   // URL parse finished.
  127.  
  128. #if wxUSE_SOCKETS
  129.   if (m_useProxy)
  130.   {
  131.     // We destroy the newly created protocol.
  132.     CleanData();
  133.  
  134.     // Third, we rebuild the URL.
  135.     m_url = m_protoname + wxT(":");
  136.     if (m_protoinfo->m_needhost)
  137.       m_url = m_url + wxT("//") + m_hostname;
  138.  
  139.     m_url += m_path;
  140.  
  141.     // We initialize specific variables.
  142.     m_protocol = m_proxy; // FIXME: we should clone the protocol
  143.   }
  144. #endif
  145.  
  146.   m_error = wxURL_NOERR;
  147.   return TRUE;
  148. }
  149.  
  150. void wxURL::CleanData()
  151. {
  152. #if wxUSE_SOCKETS
  153.   if (!m_useProxy)
  154. #endif
  155.     delete m_protocol;
  156. }
  157.  
  158. wxURL::~wxURL()
  159. {
  160.   CleanData();
  161. #if wxUSE_SOCKETS
  162.   if (m_proxy && m_proxy != ms_proxyDefault)
  163.     delete m_proxy;
  164. #endif
  165. }
  166.  
  167. // --------------------------------------------------------------
  168. // --------- wxURL urls decoders --------------------------------
  169. // --------------------------------------------------------------
  170.  
  171. bool wxURL::PrepProto(wxString& url)
  172. {
  173.   int pos;
  174.  
  175.   // Find end
  176.   pos = url.Find(wxT(':'));
  177.   if (pos == -1)
  178.     return FALSE;
  179.  
  180.   m_protoname = url(0, pos);
  181.  
  182.   url = url(pos+1, url.Length());
  183.  
  184.   return TRUE;
  185. }
  186.  
  187. bool wxURL::PrepHost(wxString& url)
  188. {
  189.   wxString temp_url;
  190.   int pos, pos2;
  191.  
  192.   if ((url.GetChar(0) != wxT('/')) || (url.GetChar(1) != wxT('/')))
  193.     return FALSE;
  194.  
  195.   url = url(2, url.Length());
  196.  
  197.   pos = url.Find(wxT('/'));
  198.   if (pos == -1)
  199.     pos = url.Length();
  200.  
  201.   if (pos == 0)
  202.     return FALSE;
  203.  
  204.   temp_url = url(0, pos);
  205.   url = url(url.Find(wxT('/')), url.Length());
  206.  
  207.   // Retrieve service number
  208.   pos2 = temp_url.Find(wxT(':'), TRUE);
  209.   if (pos2 != -1 && pos2 < pos)
  210.   {
  211.     m_servname = temp_url(pos2+1, pos);
  212.     if (!m_servname.IsNumber())
  213.       return FALSE;
  214.     temp_url = temp_url(0, pos2);
  215.   }
  216.  
  217.   // Retrieve user and password.
  218.   pos2 = temp_url.Find(wxT('@'));
  219.   // Even if pos2 equals -1, this code is right.
  220.   m_hostname = temp_url(pos2+1, temp_url.Length());
  221.  
  222.   m_user = wxT("");
  223.   m_password = wxT("");
  224.  
  225.   if (pos2 == -1)
  226.     return TRUE;
  227.  
  228.   temp_url = temp_url(0, pos2);
  229.   pos2 = temp_url.Find(wxT(':'));
  230.  
  231.   if (pos2 == -1)
  232.     return FALSE;
  233.  
  234.   m_user = temp_url(0, pos2);
  235.   m_password = temp_url(pos2+1, url.Length());
  236.  
  237.   return TRUE;
  238. }
  239.  
  240. bool wxURL::PrepPath(wxString& url)
  241. {
  242.   if (url.Length() != 0)
  243.     m_path = ConvertToValidURI(url);
  244.   else
  245.     m_path = wxT("/");
  246.   return TRUE;
  247. }
  248.  
  249. bool wxURL::FetchProtocol()
  250. {
  251.   wxProtoInfo *info = ms_protocols;
  252.  
  253.   while (info)
  254.   {
  255.     if (m_protoname == info->m_protoname)
  256.     {
  257.       if (m_servname.IsNull())
  258.         m_servname = info->m_servname;
  259.  
  260.       m_protoinfo = info;
  261.       m_protocol = (wxProtocol *)m_protoinfo->m_cinfo->CreateObject();
  262.       return TRUE;
  263.     }
  264.     info = info->next;
  265.   }
  266.   return FALSE;
  267. }
  268.  
  269. // --------------------------------------------------------------
  270. // --------- wxURL get ------------------------------------------
  271. // --------------------------------------------------------------
  272.  
  273. wxInputStream *wxURL::GetInputStream()
  274. {
  275.   wxInputStream *the_i_stream = NULL;
  276.  
  277.   if (!m_protocol)
  278.   {
  279.     m_error = wxURL_NOPROTO;
  280.     return NULL;
  281.   }
  282.  
  283.   m_error = wxURL_NOERR;
  284.   if (m_user != wxT(""))
  285.   {
  286.     m_protocol->SetUser(m_user);
  287.     m_protocol->SetPassword(m_password);
  288.   }
  289.  
  290. #if wxUSE_SOCKETS
  291.     wxIPV4address addr;
  292.  
  293.   // m_protoinfo is NULL when we use a proxy
  294.   if (!m_useProxy && m_protoinfo->m_needhost)
  295.   {
  296.     if (!addr.Hostname(m_hostname))
  297.     {
  298.       m_error = wxURL_NOHOST;
  299.       return NULL;
  300.     }
  301.  
  302.     addr.Service(m_servname);
  303.  
  304.     if (!m_protocol->Connect(addr, TRUE)) // Watcom needs the 2nd arg for some reason
  305.     {
  306.       m_error = wxURL_CONNERR;
  307.       return NULL;
  308.     }
  309.   }
  310. #endif
  311.  
  312.   // When we use a proxy, we have to pass the whole URL to it.
  313.   if (m_useProxy)
  314.     the_i_stream = m_protocol->GetInputStream(m_url);
  315.   else
  316.     the_i_stream = m_protocol->GetInputStream(m_path);
  317.  
  318.   if (!the_i_stream)
  319.   {
  320.     m_error = wxURL_PROTOERR;
  321.     return NULL;
  322.   }
  323.  
  324.   return the_i_stream;
  325. }
  326.  
  327. #if wxUSE_SOCKETS
  328. void wxURL::SetDefaultProxy(const wxString& url_proxy)
  329. {
  330.   if ( !url_proxy )
  331.   {
  332.       if ( ms_proxyDefault )
  333.       {
  334.           ms_proxyDefault->Close();
  335.           delete ms_proxyDefault;
  336.           ms_proxyDefault = NULL;
  337.       }
  338.   }
  339.   else
  340.   {
  341.       wxString tmp_str = url_proxy;
  342.       int pos = tmp_str.Find(wxT(':'));
  343.       if (pos == -1)
  344.           return;
  345.  
  346.       wxString hostname = tmp_str(0, pos),
  347.       port = tmp_str(pos+1, tmp_str.Length()-pos);
  348.       wxIPV4address addr;
  349.  
  350.       if (!addr.Hostname(hostname))
  351.           return;
  352.       if (!addr.Service(port))
  353.           return;
  354.  
  355.       if (ms_proxyDefault)
  356.           // Finally, when all is right, we connect the new proxy.
  357.           ms_proxyDefault->Close();
  358.       else
  359.           ms_proxyDefault = new wxHTTP();
  360.       ms_proxyDefault->Connect(addr, TRUE); // Watcom needs the 2nd arg for some reason
  361.   }
  362. }
  363.  
  364. void wxURL::SetProxy(const wxString& url_proxy)
  365. {
  366.     if ( !url_proxy )
  367.     {
  368.         if ( m_proxy && m_proxy != ms_proxyDefault )
  369.         {
  370.             m_proxy->Close();
  371.             delete m_proxy;
  372.         }
  373.  
  374.         m_useProxy = FALSE;
  375.     }
  376.     else
  377.     {
  378.         wxString tmp_str;
  379.         wxString hostname, port;
  380.         int pos;
  381.         wxIPV4address addr;
  382.  
  383.         tmp_str = url_proxy;
  384.         pos = tmp_str.Find(wxT(':'));
  385.         // This is an invalid proxy name.
  386.         if (pos == -1)
  387.             return;
  388.  
  389.         hostname = tmp_str(0, pos);
  390.         port = tmp_str(pos+1, tmp_str.Length()-pos);
  391.  
  392.         addr.Hostname(hostname);
  393.         addr.Service(port);
  394.  
  395.         // Finally, create the whole stuff.
  396.         if (m_proxy && m_proxy != ms_proxyDefault)
  397.             delete m_proxy;
  398.         m_proxy = new wxHTTP();
  399.         m_proxy->Connect(addr, TRUE); // Watcom needs the 2nd arg for some reason
  400.  
  401.         CleanData();
  402.         // Reparse url.
  403.         m_useProxy = TRUE;
  404.         ParseURL();
  405.     }
  406. }
  407. #endif // wxUSE_SOCKETS
  408.  
  409. wxString wxURL::ConvertToValidURI(const wxString& uri, const wxChar* delims)
  410. {
  411.   wxString out_str;
  412.   wxString hexa_code;
  413.   size_t i;
  414.  
  415.   for (i = 0; i < uri.Len(); i++)
  416.   {
  417.     wxChar c = uri.GetChar(i);
  418.  
  419.     if (c == wxT(' '))
  420.     {
  421.       // GRG, Apr/2000: changed to "%20" instead of '+'
  422.  
  423.       out_str += wxT("%20");
  424.     }
  425.     else
  426.     {
  427.       // GRG, Apr/2000: modified according to the URI definition (RFC 2396)
  428.       // 
  429.       // - Alphanumeric characters are never escaped
  430.       // - Unreserved marks are never escaped
  431.       // - Delimiters must be escaped if they appear within a component
  432.       //     but not if they are used to separate components. Here we have
  433.       //     no clear way to distinguish between these two cases, so they
  434.       //     are escaped unless they are passed in the 'delims' parameter
  435.       //     (allowed delimiters).
  436.  
  437.       static const wxChar marks[] = wxT("-_.!~*()'");
  438.  
  439.       if ( !wxIsalnum(c) && !wxStrchr(marks, c) && !wxStrchr(delims, c) )
  440.       {
  441.         hexa_code.Printf(wxT("%%%02X"), c);
  442.         out_str += hexa_code;
  443.       }
  444.       else
  445.       {
  446.         out_str += c;
  447.       }
  448.     }
  449.   }
  450.  
  451.   return out_str;
  452. }
  453.  
  454. wxString wxURL::ConvertFromURI(const wxString& uri)
  455. {
  456.   wxString new_uri;
  457.  
  458.   size_t i = 0;
  459.   while (i < uri.Len())
  460.   {
  461.     int code;
  462.     if (uri[i] == wxT('%'))
  463.     {
  464.       i++;
  465.       if (uri[i] >= wxT('A') && uri[i] <= wxT('F'))
  466.         code = (uri[i] - wxT('A') + 10) * 16;
  467.       else
  468.         code = (uri[i] - wxT('0')) * 16;
  469.  
  470.       i++;
  471.       if (uri[i] >= wxT('A') && uri[i] <= wxT('F'))
  472.         code += (uri[i] - wxT('A')) + 10;
  473.       else
  474.         code += (uri[i] - wxT('0'));
  475.  
  476.       i++;
  477.       new_uri += (wxChar)code;
  478.       continue;
  479.     }
  480.     new_uri += uri[i];
  481.     i++;
  482.   }
  483.   return new_uri;
  484. }
  485.  
  486. // ----------------------------------------------------------------------
  487. // A module which deletes the default proxy if we created it
  488. // ----------------------------------------------------------------------
  489.  
  490. #if wxUSE_SOCKETS
  491.  
  492. class wxURLModule : public wxModule
  493. {
  494. public:
  495.     virtual bool OnInit();
  496.     virtual void OnExit();
  497.  
  498. private:
  499.     DECLARE_DYNAMIC_CLASS(wxURLModule)
  500. };
  501.  
  502. IMPLEMENT_DYNAMIC_CLASS(wxURLModule, wxModule)
  503.  
  504. bool wxURLModule::OnInit()
  505. {
  506.     // env var HTTP_PROXY contains the address of the default proxy to use if
  507.     // set, but don't try to create this proxy right now because it will slow
  508.     // down the program startup (especially if there is no DNS server
  509.     // available, in which case it may take up to 1 minute)
  510.  
  511.     if ( getenv("HTTP_PROXY") )
  512.     {
  513.         wxURL::ms_useDefaultProxy = TRUE;
  514.     }
  515.  
  516.     return TRUE;
  517. }
  518.  
  519. void wxURLModule::OnExit()
  520. {
  521.     delete wxURL::ms_proxyDefault;
  522.     wxURL::ms_proxyDefault = NULL;
  523. }
  524.  
  525. #endif // wxUSE_SOCKETS
  526.  
  527. #endif // wxUSE_URL
  528.  
  529.