added wxProtocolLog class for logging network requests/responses (closes #7464)
[wxWidgets.git] / src / common / protocol.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/protocol.cpp
3 // Purpose: Implement protocol base class
4 // Author: Guilhem Lavaux
5 // Modified by:
6 // Created: 07/07/1997
7 // RCS-ID: $Id$
8 // Copyright: (c) 1997, 1998 Guilhem Lavaux
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // For compilers that support precompilation, includes "wx.h".
13 #include "wx/wxprec.h"
14
15 #ifdef __BORLANDC__
16 #pragma hdrstop
17 #endif
18
19 #if wxUSE_PROTOCOL
20
21 #include "wx/protocol/protocol.h"
22 #include "wx/protocol/log.h"
23
24 #ifndef WX_PRECOMP
25 #include "wx/module.h"
26 #endif
27
28 #include "wx/url.h"
29
30 #include <stdlib.h>
31
32 // ----------------------------------------------------------------------------
33 // wxProtoInfo
34 // ----------------------------------------------------------------------------
35
36 wxProtoInfo::wxProtoInfo(const wxChar *name, const wxChar *serv,
37 const bool need_host1, wxClassInfo *info)
38 : m_protoname(name),
39 m_servname(serv)
40 {
41 m_cinfo = info;
42 m_needhost = need_host1;
43 #if wxUSE_URL
44 next = wxURL::ms_protocols;
45 wxURL::ms_protocols = this;
46 #else
47 next = NULL;
48 #endif
49 }
50
51
52 // ----------------------------------------------------------------------------
53 // wxProtocol
54 // ----------------------------------------------------------------------------
55
56 #if wxUSE_SOCKETS
57 IMPLEMENT_ABSTRACT_CLASS(wxProtocol, wxSocketClient)
58 #else
59 IMPLEMENT_ABSTRACT_CLASS(wxProtocol, wxObject)
60 #endif
61
62 wxProtocol::wxProtocol()
63 #if wxUSE_SOCKETS
64 : wxSocketClient()
65 #endif
66 {
67 m_lastError = wxPROTO_NOERR;
68 m_log = NULL;
69 SetDefaultTimeout(60); // default timeout is 60 seconds
70 }
71
72 #if wxUSE_SOCKETS
73 bool wxProtocol::Reconnect()
74 {
75 wxIPV4address addr;
76
77 if (!GetPeer(addr))
78 {
79 Close();
80 return false;
81 }
82
83 if (!Close())
84 return false;
85
86 if (!Connect(addr))
87 return false;
88
89 return true;
90 }
91
92 void wxProtocol::SetDefaultTimeout(wxUint32 Value)
93 {
94 m_uiDefaultTimeout = Value;
95 #if wxUSE_SOCKETS
96 wxSocketBase::SetTimeout(Value); // sets it for this socket
97 #endif
98 }
99
100 wxProtocol::~wxProtocol()
101 {
102 delete m_log;
103 }
104
105 // ----------------------------------------------------------------------------
106 // Read a line from socket
107 // ----------------------------------------------------------------------------
108
109 /* static */
110 wxProtocolError wxProtocol::ReadLine(wxSocketBase *sock, wxString& result)
111 {
112 static const int LINE_BUF = 4095;
113
114 result.clear();
115
116 wxCharBuffer buf(LINE_BUF);
117 char *pBuf = buf.data();
118 while ( sock->WaitForRead() )
119 {
120 // peek at the socket to see if there is a CRLF
121 sock->Peek(pBuf, LINE_BUF);
122
123 size_t nRead = sock->LastCount();
124 if ( !nRead && sock->Error() )
125 return wxPROTO_NETERR;
126
127 // look for "\r\n" paying attention to a special case: "\r\n" could
128 // have been split by buffer boundary, so check also for \r at the end
129 // of the last chunk and \n at the beginning of this one
130 pBuf[nRead] = '\0';
131 const char *eol = strchr(pBuf, '\n');
132
133 // if we found '\n', is there a '\r' as well?
134 if ( eol )
135 {
136 if ( eol == pBuf )
137 {
138 // check for case of "\r\n" being split
139 if ( result.empty() || result.Last() != _T('\r') )
140 {
141 // ignore the stray '\n'
142 eol = NULL;
143 }
144 //else: ok, got real EOL
145
146 // read just this '\n' and restart
147 nRead = 1;
148 }
149 else // '\n' in the middle of the buffer
150 {
151 // in any case, read everything up to and including '\n'
152 nRead = eol - pBuf + 1;
153
154 if ( eol[-1] != '\r' )
155 {
156 // as above, simply ignore stray '\n'
157 eol = NULL;
158 }
159 }
160 }
161
162 sock->Read(pBuf, nRead);
163 if ( sock->LastCount() != nRead )
164 return wxPROTO_NETERR;
165
166 pBuf[nRead] = '\0';
167 result += wxString::FromAscii(pBuf);
168
169 if ( eol )
170 {
171 // remove trailing "\r\n"
172 result.RemoveLast(2);
173
174 return wxPROTO_NOERR;
175 }
176 }
177
178 return wxPROTO_NETERR;
179 }
180
181 wxProtocolError wxProtocol::ReadLine(wxString& result)
182 {
183 return ReadLine(this, result);
184 }
185
186 #endif // wxUSE_SOCKETS
187
188 // ----------------------------------------------------------------------------
189 // logging
190 // ----------------------------------------------------------------------------
191
192 void wxProtocol::SetLog(wxProtocolLog *log)
193 {
194 delete m_log;
195 m_log = log;
196 }
197
198 void wxProtocol::LogRequest(const wxString& str)
199 {
200 if ( m_log )
201 m_log->LogRequest(str);
202 }
203
204 void wxProtocol::LogResponse(const wxString& str)
205 {
206 if ( m_log )
207 m_log->LogResponse(str);
208 }
209
210 void wxProtocolLog::DoLogString(const wxString& WXUNUSED_UNLESS_DEBUG(str))
211 {
212 wxLogTrace(m_traceMask, "%s", str);
213 }
214
215 #endif // wxUSE_PROTOCOL