home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / wxos2233.zip / wxOS2-2_3_3.zip / wxWindows-2.3.3 / src / common / http.cpp < prev    next >
C/C++ Source or Header  |  2002-08-12  |  7KB  |  352 lines

  1. /////////////////////////////////////////////////////////////////////////////
  2. // Name:        http.cpp
  3. // Purpose:     HTTP protocol
  4. // Author:      Guilhem Lavaux
  5. // Modified by:
  6. // Created:     August 1997
  7. // RCS-ID:      $Id: http.cpp,v 1.49 2002/08/11 13:09:57 RR Exp $
  8. // Copyright:   (c) 1997, 1998 Guilhem Lavaux
  9. // Licence:     wxWindows license
  10. /////////////////////////////////////////////////////////////////////////////
  11.  
  12. #ifdef __GNUG__
  13.   #pragma implementation "http.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_PROTOCOL_HTTP
  24.  
  25. #include <stdio.h>
  26. #include <stdlib.h>
  27. #include "wx/string.h"
  28. #include "wx/tokenzr.h"
  29. #include "wx/socket.h"
  30. #include "wx/protocol/protocol.h"
  31. #include "wx/url.h"
  32. #include "wx/protocol/http.h"
  33. #include "wx/sckstrm.h"
  34.  
  35. IMPLEMENT_DYNAMIC_CLASS(wxHTTP, wxProtocol)
  36. IMPLEMENT_PROTOCOL(wxHTTP, wxT("http"), wxT("80"), TRUE)
  37.  
  38. #define HTTP_BSIZE 2048
  39.  
  40. wxHTTP::wxHTTP()
  41.   : wxProtocol(),
  42.     m_headers(wxKEY_STRING)
  43. {
  44.   m_addr = NULL;
  45.   m_read = FALSE;
  46.   m_proxy_mode = FALSE;
  47.  
  48.   SetNotify(wxSOCKET_LOST_FLAG);
  49. }
  50.  
  51. wxHTTP::~wxHTTP()
  52. {
  53.     ClearHeaders();
  54.  
  55.     delete m_addr;
  56. }
  57.  
  58. void wxHTTP::ClearHeaders()
  59. {
  60.   // wxString isn't a wxObject
  61.   wxNode *node = m_headers.First();
  62.   wxString *string;
  63.  
  64.   while (node) {
  65.     string = (wxString *)node->Data();
  66.     delete string;
  67.     node = node->Next();
  68.   }
  69.  
  70.   m_headers.Clear();
  71. }
  72.  
  73. wxString wxHTTP::GetContentType()
  74. {
  75.   return GetHeader(wxT("Content-Type"));
  76. }
  77.  
  78. void wxHTTP::SetProxyMode(bool on)
  79. {
  80.   m_proxy_mode = on;
  81. }
  82.  
  83. void wxHTTP::SetHeader(const wxString& header, const wxString& h_data)
  84. {
  85.   if (m_read) {
  86.     ClearHeaders();
  87.     m_read = FALSE;
  88.   }
  89.  
  90.   wxNode *node = m_headers.Find(header);
  91.  
  92.   if (!node)
  93.     m_headers.Append(header, (wxObject *)(new wxString(h_data)));
  94.   else {
  95.     wxString *str = (wxString *)node->Data();
  96.     (*str) = h_data;
  97.   }
  98. }
  99.  
  100. wxString wxHTTP::GetHeader(const wxString& header)
  101. {
  102.   wxNode *node;
  103.   wxString upper_header;
  104.  
  105.   upper_header = header.Upper();
  106.  
  107.   node = m_headers.Find(upper_header);
  108.   if (!node)
  109.     return wxEmptyString;
  110.  
  111.   return *((wxString *)node->Data());
  112. }
  113.  
  114. void wxHTTP::SendHeaders()
  115. {
  116.   wxNode *head = m_headers.First();
  117.  
  118.   while (head)
  119.   {
  120.     wxString *str = (wxString *)head->Data();
  121.  
  122.     wxString buf;
  123.     buf.Printf(wxT("%s: %s\r\n"), head->GetKeyString(), str->GetData());
  124.  
  125.     const wxWX2MBbuf cbuf = buf.mb_str();
  126.     Write(cbuf, strlen(cbuf));
  127.  
  128.     head = head->Next();
  129.   }
  130. }
  131.  
  132. bool wxHTTP::ParseHeaders()
  133. {
  134.   wxString line;
  135.   wxStringTokenizer tokenzr;
  136.  
  137.   ClearHeaders();
  138.   m_read = TRUE;
  139.  
  140. #if defined(__VISAGECPP__)
  141. // VA just can't stand while(1)
  142.     bool bOs2var = TRUE;
  143.     while(bOs2var) {
  144. #else
  145.     while (1) {
  146. #endif
  147.     m_perr = GetLine(this, line);
  148.     if (m_perr != wxPROTO_NOERR)
  149.       return FALSE;
  150.  
  151.     if (line.Length() == 0)
  152.       break;
  153.  
  154.     wxString left_str = line.BeforeFirst(':');
  155.     wxString *str = new wxString(line.AfterFirst(':').Strip(wxString::both));
  156.     left_str.MakeUpper();
  157.  
  158.     m_headers.Append(left_str, (wxObject *) str);
  159.   }
  160.   return TRUE;
  161. }
  162.  
  163. bool wxHTTP::Connect(const wxString& host)
  164. {
  165.   wxIPV4address *addr;
  166.  
  167.   if (m_addr) {
  168.     delete m_addr;
  169.     m_addr = NULL;
  170.     Close();
  171.   }
  172.  
  173.   m_addr = addr = new wxIPV4address();
  174.  
  175.   if (!addr->Hostname(host)) {
  176.     delete m_addr;
  177.     m_addr = NULL;
  178.     m_perr = wxPROTO_NETERR;
  179.     return FALSE;
  180.   }
  181.  
  182.   if (!addr->Service(wxT("http")))
  183.     addr->Service(80);
  184.  
  185.   SetHeader(wxT("Host"), host);
  186.  
  187.   return TRUE;
  188. }
  189.  
  190. bool wxHTTP::Connect(wxSockAddress& addr, bool WXUNUSED(wait))
  191. {
  192.   if (m_addr) {
  193.     delete m_addr;
  194.     Close();
  195.   }
  196.  
  197.   m_addr = addr.Clone();
  198.  
  199.   wxIPV4address *ipv4addr = wxDynamicCast(&addr, wxIPV4address);
  200.   if (ipv4addr)
  201.       SetHeader(wxT("Host"), ipv4addr->OrigHostname());
  202.  
  203.   return TRUE;
  204. }
  205.  
  206. bool wxHTTP::BuildRequest(const wxString& path, wxHTTP_Req req)
  207. {
  208.   const wxChar *request;
  209.  
  210.   switch (req) {
  211.   case wxHTTP_GET:
  212.     request = wxT("GET");
  213.     break;
  214.   default:
  215.     return FALSE;
  216.   }
  217.  
  218.   // If there is no User-Agent defined, define it.
  219.   if (GetHeader(wxT("User-Agent")).IsNull())
  220.     SetHeader(wxT("User-Agent"), wxT("wxWindows 2.x"));
  221.  
  222.   SaveState();
  223.   SetFlags(wxSOCKET_NONE);
  224.   Notify(FALSE);
  225.  
  226.   wxString buf;
  227.   buf.Printf(wxT("%s %s HTTP/1.0\r\n"), request, path.c_str());
  228.   const wxWX2MBbuf pathbuf = wxConvLocal.cWX2MB(buf);
  229.   Write(pathbuf, strlen(wxMBSTRINGCAST pathbuf));
  230.   SendHeaders();
  231.   Write("\r\n", 2);
  232.  
  233.   wxString tmp_str;
  234.   m_perr = GetLine(this, tmp_str);
  235.   if (m_perr != wxPROTO_NOERR) {
  236.     RestoreState();
  237.     return FALSE;
  238.   }
  239.  
  240.   if (!tmp_str.Contains(wxT("HTTP/"))) {
  241.     // TODO: support HTTP v0.9 which can have no header.
  242.     // FIXME: tmp_str is not put back in the in-queue of the socket.
  243.     SetHeader(wxT("Content-Length"), wxT("-1"));
  244.     SetHeader(wxT("Content-Type"), wxT("none/none"));
  245.     RestoreState();
  246.     return TRUE;
  247.   }
  248.  
  249.   wxStringTokenizer token(tmp_str,wxT(' '));
  250.   wxString tmp_str2;
  251.   bool ret_value;
  252.  
  253.   token.NextToken();
  254.   tmp_str2 = token.NextToken();
  255.  
  256.   switch (tmp_str2[0u]) {
  257.   case wxT('1'):
  258.     /* INFORMATION / SUCCESS */
  259.     break;
  260.   case wxT('2'):
  261.     /* SUCCESS */
  262.     break;
  263.   case wxT('3'):
  264.     /* REDIRECTION */
  265.     break;
  266.   default:
  267.     m_perr = wxPROTO_NOFILE;
  268.     RestoreState();
  269.     return FALSE;
  270.   }
  271.  
  272.   ret_value = ParseHeaders();
  273.   RestoreState();
  274.   return ret_value;
  275. }
  276.  
  277. class wxHTTPStream : public wxSocketInputStream
  278. {
  279. public:
  280.   wxHTTP *m_http;
  281.   size_t m_httpsize;
  282.   unsigned long m_read_bytes;
  283.  
  284.   wxHTTPStream(wxHTTP *http) : wxSocketInputStream(*http), m_http(http) {}
  285.   size_t GetSize() const { return m_httpsize; }
  286.   virtual ~wxHTTPStream(void) { m_http->Abort(); }
  287.  
  288. protected:
  289.   size_t OnSysRead(void *buffer, size_t bufsize);
  290. };
  291.  
  292. size_t wxHTTPStream::OnSysRead(void *buffer, size_t bufsize)
  293. {
  294.   size_t ret;
  295.  
  296.   if (m_httpsize > 0 && m_read_bytes >= m_httpsize)
  297.     return 0;
  298.  
  299.   ret = wxSocketInputStream::OnSysRead(buffer, bufsize);
  300.   m_read_bytes += ret;
  301.  
  302.   return ret;
  303. }
  304.  
  305. bool wxHTTP::Abort(void)
  306. {
  307.   return wxSocketClient::Close();
  308. }
  309.  
  310. wxInputStream *wxHTTP::GetInputStream(const wxString& path)
  311. {
  312.   wxHTTPStream *inp_stream;
  313.  
  314.   wxString new_path;
  315.  
  316.   m_perr = wxPROTO_CONNERR;
  317.   if (!m_addr)
  318.     return NULL;
  319.  
  320.   // We set m_connected back to FALSE so wxSocketBase will know what to do.
  321. #ifdef __WXMAC__
  322.         wxSocketClient::Connect(*m_addr , FALSE );
  323.         wxSocketClient::WaitOnConnect(10);
  324.  
  325.     if (!wxSocketClient::IsConnected())
  326.         return NULL;
  327. #else
  328.   if (!wxProtocol::Connect(*m_addr))
  329.     return NULL;
  330. #endif
  331.  
  332.   if (!BuildRequest(path, wxHTTP_GET))
  333.     return NULL;
  334.  
  335.   inp_stream = new wxHTTPStream(this);
  336.  
  337.   if (!GetHeader(wxT("Content-Length")).IsEmpty())
  338.     inp_stream->m_httpsize = wxAtoi(WXSTRINGCAST GetHeader(wxT("Content-Length")));
  339.   else
  340.     inp_stream->m_httpsize = (size_t)-1;
  341.  
  342.   inp_stream->m_read_bytes = 0;
  343.  
  344.   Notify(FALSE);
  345.   SetFlags(wxSOCKET_BLOCK | wxSOCKET_WAITALL);
  346.  
  347.   return inp_stream;
  348. }
  349.  
  350. #endif // wxUSE_PROTOCOL_HTTP
  351.  
  352.