mirror of
https://github.com/OpenVPN/openvpn3.git
synced 2024-09-20 04:02:15 +02:00
dde1574596
This is the result after running 'clang-format -i' on all C++ files and headers, with the defined formatting rules in .clang-format. Only the openvpn/common/unicode-impl.hpp has been excluded, as that is mostly a copy of an external project. Signed-off-by: David Sommerseth <davids@openvpn.net>
290 lines
7.0 KiB
C++
290 lines
7.0 KiB
C++
// OpenVPN -- An application to securely tunnel IP networks
|
|
// over a single port, with support for SSL/TLS-based
|
|
// session authentication and key exchange,
|
|
// packet encryption, packet authentication, and
|
|
// packet compression.
|
|
//
|
|
// Copyright (C) 2012-2022 OpenVPN Inc.
|
|
//
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU Affero General Public License Version 3
|
|
// as published by the Free Software Foundation.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU Affero General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU Affero General Public License
|
|
// along with this program in the COPYING file.
|
|
// If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
// A state machine to skip extraneous HTML in an
|
|
// HTTP CONNECT proxy response.
|
|
|
|
// Matches on typical HTML blocks:
|
|
//
|
|
// <!doctype html> ... </html>
|
|
// <html> ... </html>
|
|
//
|
|
// Notes:
|
|
// 1. Case insensitive
|
|
// 2. </html> can be followed by CR/LF chars
|
|
|
|
#ifndef OPENVPN_HTTP_HTMLSKIP_H
|
|
#define OPENVPN_HTTP_HTMLSKIP_H
|
|
|
|
#include <openvpn/buffer/buffer.hpp>
|
|
|
|
namespace openvpn {
|
|
namespace HTTP {
|
|
|
|
class HTMLSkip
|
|
{
|
|
public:
|
|
enum Status
|
|
{
|
|
PENDING,
|
|
MATCH,
|
|
NOMATCH,
|
|
};
|
|
|
|
HTMLSkip()
|
|
: state(INITIAL),
|
|
residual(64, 0),
|
|
bytes(0)
|
|
{
|
|
}
|
|
|
|
Status add(unsigned char c)
|
|
{
|
|
bool retain = false;
|
|
|
|
++bytes;
|
|
switch (state)
|
|
{
|
|
case INITIAL:
|
|
retain = true;
|
|
if (c == '<')
|
|
state = O_OPEN;
|
|
else
|
|
state = FAIL;
|
|
break;
|
|
case O_OPEN:
|
|
retain = true;
|
|
if (c == '!')
|
|
state = O_BANG;
|
|
else if (c == 'h' || c == 'H')
|
|
state = O_HTML_H;
|
|
else
|
|
state = FAIL;
|
|
break;
|
|
case O_BANG:
|
|
retain = true;
|
|
if (c == 'd' || c == 'D')
|
|
state = O_DOCTYPE_D;
|
|
else
|
|
state = FAIL;
|
|
break;
|
|
case O_DOCTYPE_D:
|
|
retain = true;
|
|
if (c == 'o' || c == 'O')
|
|
state = O_DOCTYPE_O;
|
|
else
|
|
state = FAIL;
|
|
break;
|
|
case O_DOCTYPE_O:
|
|
retain = true;
|
|
if (c == 'c' || c == 'C')
|
|
state = O_DOCTYPE_C;
|
|
else
|
|
state = FAIL;
|
|
break;
|
|
case O_DOCTYPE_C:
|
|
retain = true;
|
|
if (c == 't' || c == 'T')
|
|
state = O_DOCTYPE_T;
|
|
else
|
|
state = FAIL;
|
|
break;
|
|
case O_DOCTYPE_T:
|
|
retain = true;
|
|
if (c == 'y' || c == 'Y')
|
|
state = O_DOCTYPE_Y;
|
|
else
|
|
state = FAIL;
|
|
break;
|
|
case O_DOCTYPE_Y:
|
|
retain = true;
|
|
if (c == 'p' || c == 'P')
|
|
state = O_DOCTYPE_P;
|
|
else
|
|
state = FAIL;
|
|
break;
|
|
case O_DOCTYPE_P:
|
|
retain = true;
|
|
if (c == 'e' || c == 'E')
|
|
state = O_DOCTYPE_SPACE;
|
|
else
|
|
state = FAIL;
|
|
break;
|
|
case O_DOCTYPE_SPACE:
|
|
retain = true;
|
|
if (c == ' ' || c == '\t' || c == '\r' || c == '\n')
|
|
break;
|
|
else if (c == 'h' || c == 'H')
|
|
state = O_HTML_H;
|
|
else
|
|
state = FAIL;
|
|
break;
|
|
case O_HTML_H:
|
|
retain = true;
|
|
if (c == 't' || c == 'T')
|
|
state = O_HTML_T;
|
|
else
|
|
state = FAIL;
|
|
break;
|
|
case O_HTML_T:
|
|
retain = true;
|
|
if (c == 'm' || c == 'M')
|
|
state = O_HTML_M;
|
|
else
|
|
state = FAIL;
|
|
break;
|
|
case O_HTML_M:
|
|
if (c == 'l' || c == 'L')
|
|
{
|
|
state = CONTENT;
|
|
residual.reset_content();
|
|
}
|
|
else
|
|
{
|
|
state = FAIL;
|
|
retain = true;
|
|
}
|
|
break;
|
|
case CONTENT:
|
|
if (c == '<')
|
|
state = C_OPEN;
|
|
break;
|
|
case C_OPEN:
|
|
if (c == '/')
|
|
state = C_SLASH;
|
|
else
|
|
state = CONTENT;
|
|
break;
|
|
case C_SLASH:
|
|
if (c == 'h' || c == 'H')
|
|
state = C_HTML_H;
|
|
else
|
|
state = CONTENT;
|
|
break;
|
|
case C_HTML_H:
|
|
if (c == 't' || c == 'T')
|
|
state = C_HTML_T;
|
|
else
|
|
state = CONTENT;
|
|
break;
|
|
case C_HTML_T:
|
|
if (c == 'm' || c == 'M')
|
|
state = C_HTML_M;
|
|
else
|
|
state = CONTENT;
|
|
break;
|
|
case C_HTML_M:
|
|
if (c == 'l' || c == 'L')
|
|
state = C_HTML_L;
|
|
else
|
|
state = CONTENT;
|
|
break;
|
|
case C_HTML_L:
|
|
if (c == '>')
|
|
state = C_CRLF;
|
|
else
|
|
state = CONTENT;
|
|
break;
|
|
case C_CRLF:
|
|
if (!(c == '\n' || c == '\r'))
|
|
{
|
|
residual.reset_content();
|
|
residual.push_back(c);
|
|
state = DONE;
|
|
}
|
|
break;
|
|
default:
|
|
retain = true;
|
|
break;
|
|
}
|
|
|
|
if (retain)
|
|
residual.push_back(c);
|
|
|
|
switch (state)
|
|
{
|
|
case DONE:
|
|
return MATCH;
|
|
case FAIL:
|
|
return NOMATCH;
|
|
default:
|
|
return PENDING;
|
|
}
|
|
}
|
|
|
|
void get_residual(BufferAllocated &buf) const
|
|
{
|
|
if (residual.size() <= buf.offset())
|
|
{
|
|
buf.prepend(residual.c_data(), residual.size());
|
|
}
|
|
else
|
|
{
|
|
BufferAllocated newbuf(residual.size() + buf.size(), 0);
|
|
newbuf.write(residual.c_data(), residual.size());
|
|
newbuf.write(buf.c_data(), buf.size());
|
|
buf.move(newbuf);
|
|
}
|
|
}
|
|
|
|
unsigned long n_bytes() const
|
|
{
|
|
return bytes;
|
|
}
|
|
|
|
private:
|
|
enum State
|
|
{
|
|
DONE,
|
|
FAIL,
|
|
INITIAL,
|
|
O_OPEN,
|
|
O_BANG,
|
|
O_DOCTYPE_D,
|
|
O_DOCTYPE_O,
|
|
O_DOCTYPE_C,
|
|
O_DOCTYPE_T,
|
|
O_DOCTYPE_Y,
|
|
O_DOCTYPE_P,
|
|
O_DOCTYPE_SPACE,
|
|
O_HTML_H,
|
|
O_HTML_T,
|
|
O_HTML_M,
|
|
CONTENT,
|
|
C_OPEN,
|
|
C_SLASH,
|
|
C_HTML_H,
|
|
C_HTML_T,
|
|
C_HTML_M,
|
|
C_HTML_L,
|
|
C_CRLF,
|
|
};
|
|
|
|
State state;
|
|
BufferAllocated residual;
|
|
unsigned long bytes;
|
|
};
|
|
|
|
} // namespace HTTP
|
|
} // namespace openvpn
|
|
|
|
#endif
|