Added IsSupportingRTP function to simplify detecting when STUN supports RTP
[pwlib.git] / src / ptclib / shttpsvc.cxx
bloba2724efac8998c435ee808b44f2e96daddf97463
1 /*
2 * shttpsvc.cxx
4 * Class for secure service applications using HTTPS as the user interface.
6 * Portable Windows Library
8 * Copyright (c) 2001-2002 Equivalence Pty. Ltd.
10 * The contents of this file are subject to the Mozilla Public License
11 * Version 1.0 (the "License"); you may not use this file except in
12 * compliance with the License. You may obtain a copy of the License at
13 * http://www.mozilla.org/MPL/
15 * Software distributed under the License is distributed on an "AS IS"
16 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
17 * the License for the specific language governing rights and limitations
18 * under the License.
20 * The Original Code is Portable Windows Library.
22 * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
24 * Contributor(s): ______________________________________.
26 * $Log$
27 * Revision 1.11 2004/04/24 03:58:15 rjongbloed
28 * Allow for run time enable/disable of secure web access to HTTP process,
29 * changed from old debug only hack to "correct" usager. Thanks Ben Lear
31 * Revision 1.10 2002/11/06 22:47:25 robertj
32 * Fixed header comment (copyright etc)
34 * Revision 1.9 2002/08/05 05:40:45 robertj
35 * Fixed missing pragma interface/implementation
37 * Revision 1.8 2001/12/13 09:19:32 robertj
38 * Added ability to create HTTP server certificate if one does not exist.
40 * Revision 1.7 2001/09/10 02:51:23 robertj
41 * Major change to fix problem with error codes being corrupted in a
42 * PChannel when have simultaneous reads and writes in threads.
44 * Revision 1.6 2001/08/28 06:44:45 craigs
45 * Added ability to override PHTTPServer creation
47 * Revision 1.5 2001/05/24 01:01:28 robertj
48 * Fixed GNU C++ warning
50 * Revision 1.4 2001/05/16 06:02:37 craigs
51 * Changed to allow detection of non-SSL connection to SecureHTTPServiceProcess
53 * Revision 1.3 2001/05/07 23:27:06 robertj
54 * Added SO_LINGER setting to HTTP sockets to help with clearing up sockets
55 * when the application exits, which prevents new run of app as "port in use".
57 * Revision 1.2 2001/03/27 03:55:48 craigs
58 * Added hack to allow secure servers to act as non-secure servers
60 * Revision 1.1 2001/02/15 02:41:14 robertj
61 * Added class to do secure HTTP based service process.
65 #include <ptlib.h>
67 #ifdef __GNUC__
68 #pragma implementation "shttpsvc.h"
69 #endif
71 #include <ptclib/shttpsvc.h>
75 class HTTP_PSSLChannel : public PSSLChannel
77 PCLASSINFO(HTTP_PSSLChannel, PSSLChannel);
79 public:
80 HTTP_PSSLChannel(PSecureHTTPServiceProcess * svc, PSSLContext * context = NULL);
82 virtual BOOL RawSSLRead(void * buf, PINDEX & len);
84 protected:
85 enum { PreRead_Size = 4 };
87 PSecureHTTPServiceProcess * svc;
88 PINDEX preReadLen;
89 char preRead[PreRead_Size];
92 #define new PNEW
95 PSecureHTTPServiceProcess::PSecureHTTPServiceProcess(const Info & inf)
96 : PHTTPServiceProcess(inf)
98 sslContext = new PSSLContext;
99 disableSSL = FALSE;
103 PSecureHTTPServiceProcess::~PSecureHTTPServiceProcess()
105 delete sslContext;
109 PHTTPServer * PSecureHTTPServiceProcess::CreateHTTPServer(PTCPSocket & socket)
111 if (disableSSL)
112 return PHTTPServiceProcess::CreateHTTPServer(socket);
114 #ifdef SO_LINGER
115 const linger ling = { 1, 5 };
116 socket.SetOption(SO_LINGER, &ling, sizeof(ling));
117 #endif
119 PSSLChannel * ssl = new HTTP_PSSLChannel(this, sslContext);
121 if (!ssl->Accept(socket)) {
122 PSYSTEMLOG(Error, "HTTPS\tAccept failed: " << ssl->GetErrorText());
123 delete ssl;
124 return NULL;
127 PHTTPServer * server = OnCreateHTTPServer(httpNameSpace);
129 server->GetConnectionInfo().SetPersistenceMaximumTransations(0);
130 if (server->Open(ssl))
131 return server;
133 delete server;
134 return NULL;
138 BOOL PSecureHTTPServiceProcess::SetServerCertificate(const PFilePath & certificateFile,
139 BOOL create,
140 const char * dn)
142 if (create && !PFile::Exists(certificateFile)) {
143 PSSLPrivateKey key(1024);
144 PSSLCertificate certificate;
145 PStringStream name;
146 if (dn != NULL)
147 name << dn;
148 else {
149 name << "/O=" << GetManufacturer()
150 << "/CN=" << GetName() << '@' << PIPSocket::GetHostName();
152 if (!certificate.CreateRoot(name, key)) {
153 PTRACE(0, "MTGW\tCould not create certificate");
154 return FALSE;
156 certificate.Save(certificateFile);
157 key.Save(certificateFile, TRUE);
160 return sslContext->UseCertificate(certificateFile) &&
161 sslContext->UsePrivateKey(certificateFile);
164 BOOL PSecureHTTPServiceProcess::OnDetectedNonSSLConnection(PChannel * chan, const PString & line)
166 // get the MIME info
167 PMIMEInfo mime(*chan);
169 PString url;
171 // get the host field
172 PString host = mime("host");
173 if (!host.IsEmpty()) {
175 // parse the command
176 PINDEX pos = line.Find(' ');
177 if (pos != P_MAX_INDEX) {
178 PString str = line.Mid(pos).Trim();
179 pos = str.FindLast(' ');
180 if (pos != P_MAX_INDEX)
181 url = host + str.Left(pos);
185 // no URL was available, return something!
186 if (url.IsEmpty()) {
187 if (!host.IsEmpty())
188 url = host;
189 else {
190 PIPSocket::Address addr;
191 PIPSocket::GetHostAddress(addr);
192 url = addr.AsString() + ":" + PString(PString::Unsigned, httpListeningSocket->GetPort());
196 PString str = CreateNonSSLMessage(PString("http://") + url);
198 chan->WriteString(str);
199 chan->Close();
201 return FALSE;
204 PString PSecureHTTPServiceProcess::CreateNonSSLMessage(const PString & url)
206 PString newUrl = url;
207 if (url.Left(5) == "http:")
208 newUrl = PString("https:") + newUrl.Mid(5);
209 return CreateRedirectMessage(newUrl);
212 PString PSecureHTTPServiceProcess::CreateRedirectMessage(const PString & url)
214 return PString("HTTP/1.1 301 Moved Permanently\r\n") +
215 "Location: " + url + "\r\n" +
216 "\r\n";
219 HTTP_PSSLChannel::HTTP_PSSLChannel(PSecureHTTPServiceProcess * _svc, PSSLContext * context)
220 : PSSLChannel(context), svc(_svc)
222 preReadLen = P_MAX_INDEX;
226 BOOL HTTP_PSSLChannel::RawSSLRead(void * buf, PINDEX & len)
228 if (preReadLen == 0)
229 return PSSLChannel::RawSSLRead(buf, len);
231 if (preReadLen == P_MAX_INDEX) {
232 PChannel * chan = GetReadChannel();
234 // read some bytes from the channel
235 preReadLen = 0;
236 while (preReadLen < PreRead_Size) {
237 BOOL b = chan->Read(preRead + preReadLen, PreRead_Size - preReadLen);
238 if (!b)
239 break;
240 preReadLen += chan->GetLastReadCount();
243 // see if these bytes correspond to a GET or POST
244 if (
245 (preReadLen == PreRead_Size) &&
246 ((strncmp(preRead, "GET", 3) == 0) || (strncmp(preRead, "POST", 4) == 0))
249 // read in the rest of the line
250 PString line(preRead, 4);
251 int ch;
252 while (((ch = chan->ReadChar()) > 0) && (ch != '\n'))
253 line += (char)ch;
255 if (!svc->OnDetectedNonSSLConnection(chan, line))
256 return FALSE;
260 // copy some bytes to the returned buffer, but no more than the buffer will allow
261 len = PMIN(len, preReadLen);
262 memcpy(buf, preRead, len);
263 preReadLen -= len;
264 return TRUE;
269 // End Of File ///////////////////////////////////////////////////////////////