1
0
mirror of https://github.com/VCMP-SqMod/SqMod.git synced 2026-06-16 23:07:10 +02:00

Major plugin refactor and cleanup.

Switched to POCO library for unified platform/library interface.
Deprecated the external module API. It was creating more problems than solving.
Removed most built-in libraries in favor of system libraries for easier maintenance.
Cleaned and secured code with help from static analyzers.
This commit is contained in:
Sandu Liviu Catalin
2021-01-30 08:51:39 +02:00
parent e0e34b4030
commit 4a6bfc086c
6219 changed files with 1209835 additions and 454916 deletions
+109
View File
@@ -0,0 +1,109 @@
//
// AbstractHTTPRequestHandler.cpp
//
// Library: Net
// Package: HTTPServer
// Module: AbstractHTTPRequestHandler
//
// Copyright (c) 2007, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/AbstractHTTPRequestHandler.h"
#include "Poco/Net/HTTPServerRequest.h"
#include "Poco/Net/HTTPServerResponse.h"
#include "Poco/Net/HTMLForm.h"
#include "Poco/NumberFormatter.h"
#include "Poco/Exception.h"
using Poco::NumberFormatter;
namespace Poco {
namespace Net {
AbstractHTTPRequestHandler::AbstractHTTPRequestHandler():
_pRequest(0),
_pResponse(0),
_pForm(0)
{
}
AbstractHTTPRequestHandler::~AbstractHTTPRequestHandler()
{
delete _pForm;
}
void AbstractHTTPRequestHandler::handleRequest(HTTPServerRequest& request, HTTPServerResponse& response)
{
_pRequest = &request;
_pResponse = &response;
if (authenticate())
{
try
{
run();
}
catch (Poco::Exception& exc)
{
if (!response.sent())
{
sendErrorResponse(HTTPResponse::HTTP_INTERNAL_SERVER_ERROR, exc.displayText());
}
}
catch (std::exception& exc)
{
if (!response.sent())
{
sendErrorResponse(HTTPResponse::HTTP_INTERNAL_SERVER_ERROR, exc.what());
}
}
}
else
{
sendErrorResponse(HTTPResponse::HTTP_UNAUTHORIZED, "");
}
}
bool AbstractHTTPRequestHandler::authenticate()
{
return true;
}
HTMLForm& AbstractHTTPRequestHandler::form()
{
if (!_pForm)
_pForm = new HTMLForm(request(), request().stream());
return *_pForm;
}
void AbstractHTTPRequestHandler::sendErrorResponse(HTTPResponse::HTTPStatus status, const std::string& message)
{
response().setStatusAndReason(status);
std::string statusAndReason(NumberFormatter::format(static_cast<int>(response().getStatus())));
statusAndReason += " - ";
statusAndReason += response().getReason();
std::string page("<HTML><HEAD><TITLE>");
page += statusAndReason;
page += "</TITLE></HEAD><BODY><H1>";
page += statusAndReason;
page += "</H1>";
page += "<P>";
page += message;
page += "</P></BODY></HTML>";
response().sendBuffer(page.data(), page.size());
}
} } // namespace Poco::Net
+687
View File
@@ -0,0 +1,687 @@
//
// DNS.cpp
//
// Library: Net
// Package: NetCore
// Module: DNS
//
// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/DNS.h"
#include "Poco/Net/NetException.h"
#include "Poco/Net/SocketAddress.h"
#include "Poco/Environment.h"
#include "Poco/NumberFormatter.h"
#include "Poco/RWLock.h"
#include "Poco/TextIterator.h"
#include "Poco/TextConverter.h"
#include "Poco/UTF8Encoding.h"
#include "Poco/UTF32Encoding.h"
#include "Poco/Unicode.h"
#include <cstring>
#if defined(POCO_HAVE_LIBRESOLV)
#include <resolv.h>
#endif
using Poco::Environment;
using Poco::NumberFormatter;
using Poco::IOException;
namespace Poco {
namespace Net {
typedef Poco::UInt32 punycode_uint;
enum
{
punycode_success = 0,
punycode_overflow = -1,
punycode_big_output = -2,
punycode_bad_input = -3
};
static int punycode_encode(size_t input_length, const punycode_uint input[], size_t* output_length, char output[]);
static int punycode_decode(size_t input_length, const char input[], size_t* output_length, punycode_uint output[]);
#if defined(POCO_HAVE_LIBRESOLV)
static Poco::RWLock resolverLock;
#endif
HostEntry DNS::hostByName(const std::string& hostname, unsigned
#ifdef POCO_HAVE_ADDRINFO
hintFlags
#endif
)
{
#if defined(POCO_HAVE_LIBRESOLV)
Poco::ScopedReadRWLock readLock(resolverLock);
#endif
#if defined(POCO_HAVE_ADDRINFO)
struct addrinfo* pAI;
struct addrinfo hints;
std::memset(&hints, 0, sizeof(hints));
hints.ai_flags = hintFlags;
int rc = getaddrinfo(hostname.c_str(), NULL, &hints, &pAI);
if (rc == 0)
{
HostEntry result(pAI);
freeaddrinfo(pAI);
return result;
}
else
{
aierror(rc, hostname);
}
#elif defined(POCO_VXWORKS)
int addr = hostGetByName(const_cast<char*>(hostname.c_str()));
if (addr != ERROR)
{
return HostEntry(hostname, IPAddress(&addr, sizeof(addr)));
}
#else
struct hostent* he = gethostbyname(hostname.c_str());
if (he)
{
return HostEntry(he);
}
#endif
error(lastError(), hostname); // will throw an appropriate exception
throw NetException(); // to silence compiler
}
HostEntry DNS::hostByAddress(const IPAddress& address, unsigned
#ifdef POCO_HAVE_ADDRINFO
hintFlags
#endif
)
{
#if defined(POCO_HAVE_LIBRESOLV)
Poco::ScopedReadRWLock readLock(resolverLock);
#endif
#if defined(POCO_HAVE_ADDRINFO)
SocketAddress sa(address, 0);
static char fqname[1024];
int rc = getnameinfo(sa.addr(), sa.length(), fqname, sizeof(fqname), NULL, 0, NI_NAMEREQD);
if (rc == 0)
{
struct addrinfo* pAI;
struct addrinfo hints;
std::memset(&hints, 0, sizeof(hints));
hints.ai_flags = hintFlags;
rc = getaddrinfo(fqname, NULL, &hints, &pAI);
if (rc == 0)
{
HostEntry result(pAI);
freeaddrinfo(pAI);
return result;
}
else
{
aierror(rc, address.toString());
}
}
else
{
aierror(rc, address.toString());
}
#elif defined(POCO_VXWORKS)
char name[MAXHOSTNAMELEN + 1];
if (hostGetByAddr(*reinterpret_cast<const int*>(address.addr()), name) == OK)
{
return HostEntry(std::string(name), address);
}
#else
struct hostent* he = gethostbyaddr(reinterpret_cast<const char*>(address.addr()), address.length(), address.af());
if (he)
{
return HostEntry(he);
}
#endif
int err = lastError();
error(err, address.toString()); // will throw an appropriate exception
throw NetException(); // to silence compiler
}
HostEntry DNS::resolve(const std::string& address)
{
IPAddress ip;
if (IPAddress::tryParse(address, ip))
{
return hostByAddress(ip);
}
else if (isIDN(address))
{
std::string encoded = encodeIDN(address);
return hostByName(encoded);
}
else
{
return hostByName(address);
}
}
IPAddress DNS::resolveOne(const std::string& address)
{
const HostEntry& entry = resolve(address);
if (!entry.addresses().empty())
return entry.addresses()[0];
else
throw NoAddressFoundException(address);
}
HostEntry DNS::thisHost()
{
return hostByName(hostName());
}
void DNS::reload()
{
#if defined(POCO_HAVE_LIBRESOLV)
Poco::ScopedWriteRWLock writeLock(resolverLock);
res_init();
#endif
}
std::string DNS::hostName()
{
char buffer[256];
int rc = gethostname(buffer, sizeof(buffer));
if (rc == 0)
return std::string(buffer);
else
throw NetException("Cannot get host name");
}
bool DNS::isIDN(const std::string& hostname)
{
for (auto ch: hostname)
{
if (static_cast<unsigned char>(ch) >= 0x80) return true;
}
return false;
}
bool DNS::isEncodedIDN(const std::string& hostname)
{
return hostname.compare(0, 4, "xn--") == 0 || hostname.find(".xn--") != std::string::npos;
}
std::string DNS::encodeIDN(const std::string& idn)
{
std::string encoded;
std::string::const_iterator it = idn.begin();
std::string::const_iterator end = idn.end();
while (it != end)
{
std::string label;
bool mustEncode = false;
while (it != end && *it != '.')
{
if (static_cast<unsigned char>(*it) >= 0x80) mustEncode = true;
label += *it++;
}
if (mustEncode)
encoded += encodeIDNLabel(label);
else
encoded += label;
if (it != end) encoded += *it++;
}
return encoded;
}
std::string DNS::decodeIDN(const std::string& encodedIDN)
{
std::string decoded;
std::string::const_iterator it = encodedIDN.begin();
std::string::const_iterator end = encodedIDN.end();
while (it != end)
{
std::string label;
while (it != end && *it != '.')
{
label += *it++;
}
decoded += decodeIDNLabel(label);
if (it != end) decoded += *it++;
}
return decoded;
}
std::string DNS::encodeIDNLabel(const std::string& label)
{
std::string encoded = "xn--";
std::vector<Poco::UInt32> uniLabel;
Poco::UTF8Encoding utf8;
Poco::TextIterator it(label, utf8);
Poco::TextIterator end(label);
while (it != end)
{
int ch = *it;
if (ch < 0) throw DNSException("Invalid UTF-8 character in IDN label", label);
if (Poco::Unicode::isUpper(ch))
{
ch = Poco::Unicode::toLower(ch);
}
uniLabel.push_back(static_cast<Poco::UInt32>(ch));
++it;
}
char buffer[64];
std::size_t size = 64;
int rc = punycode_encode(uniLabel.size(), &uniLabel[0], &size, buffer);
if (rc == punycode_success)
encoded.append(buffer, size);
else
throw DNSException("Failed to encode IDN label", label);
return encoded;
}
std::string DNS::decodeIDNLabel(const std::string& encodedIDN)
{
std::string decoded;
if (encodedIDN.compare(0, 4, "xn--") == 0)
{
std::size_t size = 64;
punycode_uint buffer[64];
int rc = punycode_decode(encodedIDN.size() - 4, encodedIDN.data() + 4, &size, buffer);
if (rc == punycode_success)
{
Poco::UTF32Encoding utf32;
Poco::UTF8Encoding utf8;
Poco::TextConverter converter(utf32, utf8);
converter.convert(buffer, static_cast<int>(size*sizeof(punycode_uint)), decoded);
}
else throw DNSException("Failed to decode IDN label: ", encodedIDN);
}
else
{
decoded = encodedIDN;
}
return decoded;
}
int DNS::lastError()
{
#if defined(_WIN32)
return GetLastError();
#elif defined(POCO_VXWORKS)
return errno;
#else
return h_errno;
#endif
}
void DNS::error(int code, const std::string& arg)
{
switch (code)
{
case POCO_ESYSNOTREADY:
throw NetException("Net subsystem not ready");
case POCO_ENOTINIT:
throw NetException("Net subsystem not initialized");
case POCO_HOST_NOT_FOUND:
throw HostNotFoundException(arg);
case POCO_TRY_AGAIN:
throw DNSException("Temporary DNS error while resolving", arg);
case POCO_NO_RECOVERY:
throw DNSException("Non recoverable DNS error while resolving", arg);
case POCO_NO_DATA:
throw NoAddressFoundException(arg);
default:
throw IOException(NumberFormatter::format(code));
}
}
void DNS::aierror(int code, const std::string& arg)
{
#if defined(POCO_HAVE_IPv6) || defined(POCO_HAVE_ADDRINFO)
switch (code)
{
case EAI_AGAIN:
throw DNSException("Temporary DNS error while resolving", arg);
case EAI_FAIL:
throw DNSException("Non recoverable DNS error while resolving", arg);
#if !defined(_WIN32) // EAI_NODATA and EAI_NONAME have the same value
#if defined(EAI_NODATA) // deprecated in favor of EAI_NONAME on FreeBSD
case EAI_NODATA:
throw NoAddressFoundException(arg);
#endif
#endif
case EAI_NONAME:
throw HostNotFoundException(arg);
#if defined(EAI_SYSTEM)
case EAI_SYSTEM:
error(lastError(), arg);
break;
#endif
#if defined(_WIN32)
case WSANO_DATA: // may happen on XP
throw HostNotFoundException(arg);
#endif
default:
throw DNSException("EAI", NumberFormatter::format(code));
}
#endif // POCO_HAVE_IPv6 || defined(POCO_HAVE_ADDRINFO)
}
/*
Code copied from http://www.nicemice.net/idn/punycode-spec.gz on
2018-02-17 with SHA-1 a966a8017f6be579d74a50a226accc7607c40133
labeled punycode-spec 1.0.3 (2006-Mar-23-Thu).
Modified for POCO C++ Libraries by Guenter Obiltschnig.
License on the original code:
punycode-spec 1.0.3 (2006-Mar-23-Thu)
http://www.nicemice.net/idn/
Adam M. Costello
http://www.nicemice.net/amc/
B. Disclaimer and license
Regarding this entire document or any portion of it (including
the pseudocode and C code), the author makes no guarantees and
is not responsible for any damage resulting from its use. The
author grants irrevocable permission to anyone to use, modify,
and distribute it in any way that does not diminish the rights
of anyone else to use, modify, and distribute it, provided that
redistributed derivative works do not contain misleading author or
version information. Derivative works need not be licensed under
similar terms.
C. Punycode sample implementation
punycode-sample.c 2.0.0 (2004-Mar-21-Sun)
http://www.nicemice.net/idn/
Adam M. Costello
http://www.nicemice.net/amc/
This is ANSI C code (C89) implementing Punycode 1.0.x.
*/
/*** Bootstring parameters for Punycode ***/
enum
{
base = 36,
tmin = 1,
tmax = 26,
skew = 38,
damp = 700,
initial_bias = 72,
initial_n = 0x80,
delimiter = 0x2D
};
/* basic(cp) tests whether cp is a basic code point: */
#define basic(cp) ((punycode_uint)(cp) < 0x80)
/* delim(cp) tests whether cp is a delimiter: */
#define delim(cp) ((cp) == delimiter)
/* encode_digit(d,flag) returns the basic code point whose value */
/* (when used for representing integers) is d, which needs to be in */
/* the range 0 to base-1. The lowercase form is used unless flag is */
/* nonzero, in which case the uppercase form is used. The behavior */
/* is undefined if flag is nonzero and digit d has no uppercase form. */
static char encode_digit(punycode_uint d, int flag)
{
return d + 22 + 75 * (d < 26) - ((flag != 0) << 5);
/* 0..25 map to ASCII a..z or A..Z */
/* 26..35 map to ASCII 0..9 */
}
/* decode_digit(cp) returns the numeric value of a basic code */
/* point (for use in representing integers) in the range 0 to */
/* base-1, or base if cp does not represent a value. */
static unsigned decode_digit(int cp)
{
return (unsigned) (cp - 48 < 10 ? cp - 22 : cp - 65 < 26 ? cp - 65 :
cp - 97 < 26 ? cp - 97 : base);
}
/*** Platform-specific constants ***/
/* maxint is the maximum value of a punycode_uint variable: */
static const punycode_uint maxint = -1;
/* Because maxint is unsigned, -1 becomes the maximum value. */
/*** Bias adaptation function ***/
static punycode_uint adapt(punycode_uint delta, punycode_uint numpoints, int firsttime);
static punycode_uint adapt(punycode_uint delta, punycode_uint numpoints, int firsttime)
{
punycode_uint k;
delta = firsttime ? delta / damp : delta >> 1;
/* delta >> 1 is a faster way of doing delta / 2 */
delta += delta / numpoints;
for (k = 0; delta > ((base - tmin) * tmax) / 2; k += base)
{
delta /= base - tmin;
}
return k + (base - tmin + 1) * delta / (delta + skew);
}
/*** Main encode function ***/
int punycode_encode(size_t input_length_orig, const punycode_uint input[], size_t *output_length, char output[])
{
punycode_uint input_length, n, delta, h, b, bias, j, m, q, k, t;
size_t out, max_out;
/* The Punycode spec assumes that the input length is the same type */
/* of integer as a code point, so we need to convert the size_t to */
/* a punycode_uint, which could overflow. */
if (input_length_orig > maxint) return punycode_overflow;
input_length = (punycode_uint) input_length_orig;
/* Initialize the state: */
n = initial_n;
delta = 0;
out = 0;
max_out = *output_length;
bias = initial_bias;
/* Handle the basic code points: */
for (j = 0; j < input_length; ++j)
{
if (basic(input[j]))
{
if (max_out - out < 2) return punycode_big_output;
output[out++] = (char) input[j];
}
/* else if (input[j] < n) return punycode_bad_input; */
/* (not needed for Punycode with unsigned code points) */
}
h = b = (punycode_uint) out;
/* cannot overflow because out <= input_length <= maxint */
/* h is the number of code points that have been handled, b is the */
/* number of basic code points, and out is the number of ASCII code */
/* points that have been output. */
if (b > 0) output[out++] = delimiter;
/* Main encoding loop: */
while (h < input_length)
{
/* All non-basic code points < n have been */
/* handled already. Find the next larger one: */
for (m = maxint, j = 0; j < input_length; ++j)
{
/* if (basic(input[j])) continue; */
/* (not needed for Punycode) */
if (input[j] >= n && input[j] < m) m = input[j];
}
/* Increase delta enough to advance the decoder's */
/* <n,i> state to <m,0>, but guard against overflow: */
if (m - n > (maxint - delta) / (h + 1)) return punycode_overflow;
delta += (m - n) * (h + 1);
n = m;
for (j = 0; j < input_length; ++j)
{
/* Punycode does not need to check whether input[j] is basic: */
if (input[j] < n /* || basic(input[j]) */ )
{
if (++delta == 0) return punycode_overflow;
}
if (input[j] == n)
{
/* Represent delta as a generalized variable-length integer: */
for (q = delta, k = base; ; k += base)
{
if (out >= max_out) return punycode_big_output;
t = k <= bias /* + tmin */ ? tmin : /* +tmin not needed */
k >= bias + tmax ? tmax : k - bias;
if (q < t) break;
output[out++] = encode_digit(t + (q - t) % (base - t), 0);
q = (q - t) / (base - t);
}
output[out++] = encode_digit(q, 0);
bias = adapt(delta, h + 1, h == b);
delta = 0;
++h;
}
}
++delta, ++n;
}
*output_length = out;
return punycode_success;
}
/*** Main decode function ***/
int punycode_decode(size_t input_length, const char input[], size_t *output_length, punycode_uint output[])
{
punycode_uint n, out, i, max_out, bias, oldi, w, k, digit, t;
size_t b, j, in;
/* Initialize the state: */
n = initial_n;
out = i = 0;
max_out = *output_length > maxint ? maxint : (punycode_uint) *output_length;
bias = initial_bias;
/* Handle the basic code points: Let b be the number of input code */
/* points before the last delimiter, or 0 if there is none, then */
/* copy the first b code points to the output. */
for (b = j = 0; j < input_length; ++j)
{
if (delim(input[j])) b = j;
}
if (b > max_out) return punycode_big_output;
for (j = 0; j < b; ++j)
{
if (!basic(input[j])) return punycode_bad_input;
output[out++] = input[j];
}
/* Main decoding loop: Start just after the last delimiter if any */
/* basic code points were copied; start at the beginning otherwise. */
for (in = b > 0 ? b + 1 : 0; in < input_length; ++out)
{
/* in is the index of the next ASCII code point to be consumed, */
/* and out is the number of code points in the output array. */
/* Decode a generalized variable-length integer into delta, */
/* which gets added to i. The overflow checking is easier */
/* if we increase i as we go, then subtract off its starting */
/* value at the end to obtain delta. */
for (oldi = i, w = 1, k = base; ; k += base)
{
if (in >= input_length) return punycode_bad_input;
digit = decode_digit(input[in++]);
if (digit >= base) return punycode_bad_input;
if (digit > (maxint - i) / w) return punycode_overflow;
i += digit * w;
t = k <= bias /* + tmin */ ? tmin : /* +tmin not needed */
k >= bias + tmax ? tmax : k - bias;
if (digit < t) break;
if (w > maxint / (base - t)) return punycode_overflow;
w *= (base - t);
}
bias = adapt(i - oldi, out + 1, oldi == 0);
/* i was supposed to wrap around from out+1 to 0, */
/* incrementing n each time, so we'll fix that now: */
if (i / (out + 1) > maxint - n) return punycode_overflow;
n += i / (out + 1);
i %= (out + 1);
/* Insert n at position i of the output: */
/* not needed for Punycode: */
/* if (basic(n)) return punycode_bad_input; */
if (out >= max_out) return punycode_big_output;
std::memmove(output + i + 1, output + i, (out - i) * sizeof *output);
output[i++] = n;
}
*output_length = (size_t) out;
/* cannot overflow because out <= old value of *output_length */
return punycode_success;
}
} } // namespace Poco::Net
+156
View File
@@ -0,0 +1,156 @@
//
// DatagramSocket.cpp
//
// Library: Net
// Package: Sockets
// Module: DatagramSocket
//
// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/DatagramSocket.h"
#include "Poco/Net/DatagramSocketImpl.h"
#include "Poco/Exception.h"
using Poco::InvalidArgumentException;
namespace Poco {
namespace Net {
DatagramSocket::DatagramSocket(): Socket(new DatagramSocketImpl)
{
}
DatagramSocket::DatagramSocket(SocketAddress::Family family): Socket(new DatagramSocketImpl(family))
{
}
DatagramSocket::DatagramSocket(const SocketAddress& address, bool reuseAddress): Socket(new DatagramSocketImpl(address.family()))
{
bind(address, reuseAddress);
}
DatagramSocket::DatagramSocket(const Socket& socket): Socket(socket)
{
if (!dynamic_cast<DatagramSocketImpl*>(impl()))
throw InvalidArgumentException("Cannot assign incompatible socket");
}
DatagramSocket::DatagramSocket(SocketImpl* pImpl): Socket(pImpl)
{
if (!dynamic_cast<DatagramSocketImpl*>(impl()))
throw InvalidArgumentException("Cannot assign incompatible socket");
}
DatagramSocket::~DatagramSocket()
{
}
DatagramSocket& DatagramSocket::operator = (const Socket& socket)
{
if (dynamic_cast<DatagramSocketImpl*>(socket.impl()))
Socket::operator = (socket);
else
throw InvalidArgumentException("Cannot assign incompatible socket");
return *this;
}
void DatagramSocket::connect(const SocketAddress& address)
{
impl()->connect(address);
}
void DatagramSocket::bind(const SocketAddress& address, bool reuseAddress)
{
impl()->bind(address, reuseAddress);
}
void DatagramSocket::bind(const SocketAddress& address, bool reuseAddress, bool reusePort)
{
impl()->bind(address, reuseAddress, reusePort);
}
int DatagramSocket::sendBytes(const void* buffer, int length, int flags)
{
return impl()->sendBytes(buffer, length, flags);
}
int DatagramSocket::sendBytes(const SocketBufVec& buffers, int flags)
{
return impl()->sendBytes(buffers, flags);
}
int DatagramSocket::receiveBytes(void* buffer, int length, int flags)
{
return impl()->receiveBytes(buffer, length, flags);
}
int DatagramSocket::receiveBytes(SocketBufVec& buffers, int flags)
{
return impl()->receiveBytes(buffers, flags);
}
int DatagramSocket::receiveBytes(Poco::Buffer<char>& buffer, int flags, const Poco::Timespan& timeout)
{
return impl()->receiveBytes(buffer, flags, timeout);
}
int DatagramSocket::sendTo(const void* buffer, int length, const SocketAddress& address, int flags)
{
return impl()->sendTo(buffer, length, address, flags);
}
int DatagramSocket::sendTo(const SocketBufVec& buffers, const SocketAddress& address, int flags)
{
return impl()->sendTo(buffers, address, flags);
}
int DatagramSocket::receiveFrom(void* buffer, int length, SocketAddress& address, int flags)
{
return impl()->receiveFrom(buffer, length, address, flags);
}
int DatagramSocket::receiveFrom(void* buffer, int length, struct sockaddr** ppSA, poco_socklen_t** saLen, int flags)
{
return impl()->receiveFrom(buffer, length, ppSA, saLen, flags);
}
int DatagramSocket::receiveFrom(SocketBufVec& buffers, SocketAddress& address, int flags)
{
return impl()->receiveFrom(buffers, address, flags);
}
int DatagramSocket::receiveFrom(SocketBufVec& buffers, struct sockaddr** ppSA, poco_socklen_t** ppSALen, int flags)
{
return impl()->receiveFrom(buffers, ppSA, ppSALen, flags);
}
} } // namespace Poco::Net
+63
View File
@@ -0,0 +1,63 @@
//
// DatagramSocketImpl.cpp
//
// Library: Net
// Package: Sockets
// Module: DatagramSocketImpl
//
// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/DatagramSocketImpl.h"
#include "Poco/Net/NetException.h"
using Poco::InvalidArgumentException;
namespace Poco {
namespace Net {
DatagramSocketImpl::DatagramSocketImpl()
{
}
DatagramSocketImpl::DatagramSocketImpl(SocketAddress::Family family)
{
if (family == SocketAddress::IPv4)
init(AF_INET);
#if defined(POCO_HAVE_IPv6)
else if (family == SocketAddress::IPv6)
init(AF_INET6);
#endif
#if defined(POCO_OS_FAMILY_UNIX)
else if (family == SocketAddress::UNIX_LOCAL)
init(AF_UNIX);
#endif
else throw InvalidArgumentException("Invalid or unsupported address family passed to DatagramSocketImpl");
}
DatagramSocketImpl::DatagramSocketImpl(poco_socket_t sockfd): SocketImpl(sockfd)
{
}
DatagramSocketImpl::~DatagramSocketImpl()
{
}
void DatagramSocketImpl::init(int af)
{
initSocket(af, SOCK_DGRAM);
}
} } // namespace Poco::Net
+295
View File
@@ -0,0 +1,295 @@
//
// DialogSocket.cpp
//
// Library: Net
// Package: Sockets
// Module: DialogSocket
//
// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/DialogSocket.h"
#include "Poco/Exception.h"
#include "Poco/Ascii.h"
#include <cstring>
namespace Poco {
namespace Net {
DialogSocket::DialogSocket():
_pBuffer(0),
_pNext(0),
_pEnd(0)
{
allocBuffer();
}
DialogSocket::DialogSocket(const SocketAddress& address):
StreamSocket(address),
_pBuffer(0),
_pNext(0),
_pEnd(0)
{
allocBuffer();
}
DialogSocket::DialogSocket(const Socket& socket):
StreamSocket(socket),
_pBuffer(0),
_pNext(0),
_pEnd(0)
{
allocBuffer();
}
DialogSocket::DialogSocket(const DialogSocket& socket):
StreamSocket(socket),
_pBuffer(0),
_pNext(0),
_pEnd(0)
{
allocBuffer();
}
DialogSocket::~DialogSocket()
{
delete [] _pBuffer;
}
DialogSocket& DialogSocket::operator = (const Socket& socket)
{
StreamSocket::operator = (socket);
_pNext = _pBuffer;
_pEnd = _pBuffer;
return *this;
}
DialogSocket& DialogSocket::operator = (const DialogSocket& socket)
{
StreamSocket::operator = (socket);
_pNext = _pBuffer;
_pEnd = _pBuffer;
return *this;
}
void DialogSocket::sendByte(unsigned char ch)
{
sendBytes(&ch, 1);
}
void DialogSocket::sendString(const char* str)
{
sendBytes(str, (int) std::strlen(str));
}
void DialogSocket::sendString(const std::string& str)
{
sendBytes(str.data(), (int) str.length());
}
void DialogSocket::sendMessage(const std::string& message)
{
std::string line;
line.reserve(message.length() + 2);
line.append(message);
line.append("\r\n");
sendString(line);
}
void DialogSocket::sendMessage(const std::string& message, const std::string& arg)
{
std::string line;
line.reserve(message.length() + arg.length() + 3);
line.append(message);
if (!arg.empty())
{
line.append(" ");
line.append(arg);
}
line.append("\r\n");
sendString(line);
}
void DialogSocket::sendMessage(const std::string& message, const std::string& arg1, const std::string& arg2)
{
std::string line;
line.reserve(message.length() + arg1.length() +arg2.length() + 4);
line.append(message);
line.append(" ");
line.append(arg1);
if (!arg2.empty())
{
line.append(" ");
line.append(arg2);
}
line.append("\r\n");
sendString(line);
}
bool DialogSocket::receiveMessage(std::string& message)
{
message.clear();
return receiveLine(message, MAX_LINE_LENGTH);
}
int DialogSocket::receiveStatusMessage(std::string& message)
{
message.clear();
int status = receiveStatusLine(message, MAX_LINE_LENGTH);
if (status < 0)
{
while (status <= 0)
{
message += '\n';
status = receiveStatusLine(message, message.length() + MAX_LINE_LENGTH);
}
}
return status;
}
int DialogSocket::get()
{
refill();
if (_pNext != _pEnd)
return std::char_traits<char>::to_int_type(*_pNext++);
else
return EOF_CHAR;
}
int DialogSocket::peek()
{
refill();
if (_pNext != _pEnd)
return std::char_traits<char>::to_int_type(*_pNext);
else
return EOF_CHAR;
}
void DialogSocket::synch()
{
sendUrgent(TELNET_DM);
}
void DialogSocket::sendTelnetCommand(unsigned char command)
{
unsigned char buffer[2];
buffer[0] = TELNET_IAC;
buffer[1] = command;
sendBytes(buffer, 2);
}
void DialogSocket::sendTelnetCommand(unsigned char command, unsigned char arg)
{
unsigned char buffer[3];
buffer[0] = TELNET_IAC;
buffer[1] = command;
buffer[2] = arg;
sendBytes(buffer, 3);
}
void DialogSocket::refill()
{
if (_pNext == _pEnd)
{
int n = receiveBytes(_pBuffer, RECEIVE_BUFFER_SIZE);
if (n > 0)
{
_pNext = _pBuffer;
_pEnd = _pBuffer + n;
}
}
}
void DialogSocket::allocBuffer()
{
_pBuffer = new char [RECEIVE_BUFFER_SIZE];
_pNext = _pBuffer;
_pEnd = _pBuffer;
}
bool DialogSocket::receiveLine(std::string& line, std::size_t lineLengthLimit)
{
// An old wisdom goes: be strict in what you emit
// and generous in what you accept.
int ch = get();
while (ch != EOF_CHAR && ch != '\r' && ch != '\n')
{
if (lineLengthLimit == 0 || line.size() < lineLengthLimit)
line += (char) ch;
else
throw Poco::IOException("Line too long");
ch = get();
}
if (ch == '\r' && peek() == '\n')
get();
else if (ch == EOF_CHAR)
return false;
return true;
}
int DialogSocket::receiveStatusLine(std::string& line, std::size_t lineLengthLimit)
{
int status = 0;
int ch = get();
if (ch != EOF_CHAR) line += (char) ch;
int n = 0;
while (Poco::Ascii::isDigit(ch) && n < 3)
{
status *= 10;
status += ch - '0';
++n;
ch = get();
if (ch != EOF_CHAR) line += (char) ch;
}
if (n == 3)
{
if (ch == '-')
status = -status;
}
else status = 0;
if (ch != EOF_CHAR) receiveLine(line, lineLengthLimit);
return status;
}
int DialogSocket::receiveRawBytes(void* buffer, int length)
{
refill();
int n = static_cast<int>(_pEnd - _pNext);
if (n > length) n = length;
std::memcpy(buffer, _pNext, n);
_pNext += n;
return n;
}
} } // namespace Poco::Net
+92
View File
@@ -0,0 +1,92 @@
//
// EscapeHTMLStream.cpp
//
// Library: Net
// Package: Mail
// Module: EscapeHTMLStream
//
// Copyright (c) 2019, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/EscapeHTMLStream.h"
namespace Poco {
namespace Net {
EscapeHTMLStreamBuf::EscapeHTMLStreamBuf(std::ostream& ostr):
_pOstr(&ostr)
{
}
EscapeHTMLStreamBuf::~EscapeHTMLStreamBuf()
{
}
int EscapeHTMLStreamBuf::readFromDevice()
{
return std::char_traits<char>::eof();
}
int EscapeHTMLStreamBuf::writeToDevice(char c)
{
switch (c)
{
case '<':
*_pOstr << "&lt;";
break;
case '>':
*_pOstr << "&gt;";
break;
case '"':
*_pOstr << "&quot;";
break;
case '&':
*_pOstr << "&amp;";
break;
default:
_pOstr->put(c);
break;
}
return charToInt(c);
}
EscapeHTMLIOS::EscapeHTMLIOS(std::ostream& ostr): _buf(ostr)
{
poco_ios_init(&_buf);
}
EscapeHTMLIOS::~EscapeHTMLIOS()
{
}
EscapeHTMLStreamBuf* EscapeHTMLIOS::rdbuf()
{
return &_buf;
}
EscapeHTMLOutputStream::EscapeHTMLOutputStream(std::ostream& ostr):
EscapeHTMLIOS(ostr),
std::ostream(&_buf)
{
}
EscapeHTMLOutputStream::~EscapeHTMLOutputStream()
{
}
} } // namespace Poco::Net
+631
View File
@@ -0,0 +1,631 @@
//
// FTPClientSession.cpp
//
// Library: Net
// Package: FTP
// Module: FTPClientSession
//
// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/FTPClientSession.h"
#include "Poco/Net/SocketAddress.h"
#include "Poco/Net/SocketStream.h"
#include "Poco/Net/ServerSocket.h"
#include "Poco/Net/NetException.h"
#include "Poco/NumberFormatter.h"
#include "Poco/Ascii.h"
using Poco::NumberFormatter;
namespace Poco {
namespace Net {
FTPClientSession::FTPClientSession():
_pControlSocket(0),
_pDataStream(0),
_port(FTP_PORT),
_passiveMode(true),
_fileType(TYPE_BINARY),
_supports1738(true),
_serverReady(false),
_isLoggedIn(false),
_timeout(DEFAULT_TIMEOUT)
{
}
FTPClientSession::FTPClientSession(const StreamSocket& socket, bool readWelcomeMessage):
_pControlSocket(new DialogSocket(socket)),
_pDataStream(0),
_host(socket.address().host().toString()),
_port(socket.address().port()),
_passiveMode(true),
_fileType(TYPE_BINARY),
_supports1738(true),
_serverReady(false),
_isLoggedIn(false),
_timeout(DEFAULT_TIMEOUT)
{
_pControlSocket->setReceiveTimeout(_timeout);
if (readWelcomeMessage)
{
receiveServerReadyReply();
}
else
{
_serverReady = true;
}
}
FTPClientSession::FTPClientSession(const std::string& host,
Poco::UInt16 port,
const std::string& username,
const std::string& password):
_pControlSocket(new DialogSocket(SocketAddress(host, port))),
_pDataStream(0),
_host(host),
_port(port),
_passiveMode(true),
_fileType(TYPE_BINARY),
_supports1738(true),
_serverReady(false),
_isLoggedIn(false),
_timeout(DEFAULT_TIMEOUT)
{
_pControlSocket->setReceiveTimeout(_timeout);
if (!username.empty())
login(username, password);
}
FTPClientSession::~FTPClientSession()
{
try
{
close();
}
catch (...)
{
}
}
void FTPClientSession::setTimeout(const Poco::Timespan& timeout)
{
if (!isOpen())
throw FTPException("Connection is closed.");
_timeout = timeout;
_pControlSocket->setReceiveTimeout(timeout);
}
Poco::Timespan FTPClientSession::getTimeout() const
{
return _timeout;
}
void FTPClientSession::setPassive(bool flag, bool useRFC1738)
{
_passiveMode = flag;
_supports1738 = useRFC1738;
}
bool FTPClientSession::getPassive() const
{
return _passiveMode;
}
void FTPClientSession::open(const std::string& host,
Poco::UInt16 port,
const std::string& username,
const std::string& password)
{
_host = host;
_port = port;
if (!username.empty())
{
login(username, password);
}
else
{
if (!_pControlSocket)
{
_pControlSocket = new DialogSocket(SocketAddress(_host, _port));
_pControlSocket->setReceiveTimeout(_timeout);
}
receiveServerReadyReply();
}
}
void FTPClientSession::receiveServerReadyReply()
{
if (_serverReady) return;
std::string response;
int status = _pControlSocket->receiveStatusMessage(response);
if (!isPositiveCompletion(status))
throw FTPException("Cannot receive status message", response, status);
{
Poco::FastMutex::ScopedLock lock(_wmMutex);
_welcomeMessage = response;
}
_serverReady = true;
}
void FTPClientSession::login(const std::string& username, const std::string& password)
{
if (_isLoggedIn) logout();
int status = FTP_POSITIVE_COMPLETION * 100;
std::string response;
if (!_pControlSocket)
{
_pControlSocket = new DialogSocket(SocketAddress(_host, _port));
_pControlSocket->setReceiveTimeout(_timeout);
}
receiveServerReadyReply();
status = sendCommand("USER", username, response);
if (isPositiveIntermediate(status))
status = sendCommand("PASS", password, response);
if (!isPositiveCompletion(status))
throw FTPException("Login denied", response, status);
setFileType(_fileType);
_isLoggedIn = true;
}
void FTPClientSession::logout()
{
if (!isOpen())
throw FTPException("Connection is closed.");
if (_isLoggedIn)
{
try
{
endTransfer();
}
catch (...)
{
}
_isLoggedIn = false;
std::string response;
sendCommand("QUIT", response);
}
}
void FTPClientSession::close()
{
try
{
logout();
}
catch (...)
{
}
_serverReady = false;
if (_pControlSocket)
{
_pControlSocket->close();
delete _pControlSocket;
_pControlSocket = 0;
}
}
void FTPClientSession::setFileType(FTPClientSession::FileType type)
{
std::string response;
int status = sendCommand("TYPE", (type == TYPE_TEXT ? "A" : "I"), response);
if (!isPositiveCompletion(status)) throw FTPException("Cannot set file type", response, status);
_fileType = type;
}
FTPClientSession::FileType FTPClientSession::getFileType() const
{
return _fileType;
}
std::string FTPClientSession::systemType()
{
std::string response;
int status = sendCommand("SYST", response);
if (isPositiveCompletion(status))
return response.substr(4);
else
throw FTPException("Cannot get remote system type", response, status);
}
void FTPClientSession::setWorkingDirectory(const std::string& path)
{
std::string response;
int status = sendCommand("CWD", path, response);
if (!isPositiveCompletion(status))
throw FTPException("Cannot change directory", response, status);
}
std::string FTPClientSession::getWorkingDirectory()
{
std::string response;
int status = sendCommand("PWD", response);
if (isPositiveCompletion(status))
return extractPath(response);
else
throw FTPException("Cannot get current working directory", response, status);
}
void FTPClientSession::cdup()
{
std::string response;
int status = sendCommand("CDUP", response);
if (!isPositiveCompletion(status))
throw FTPException("Cannot change directory", response, status);
}
void FTPClientSession::rename(const std::string& oldName, const std::string& newName)
{
std::string response;
int status = sendCommand("RNFR", oldName, response);
if (!isPositiveIntermediate(status))
throw FTPException(std::string("Cannot rename ") + oldName, response, status);
status = sendCommand("RNTO", newName, response);
if (!isPositiveCompletion(status))
throw FTPException(std::string("Cannot rename to ") + newName, response, status);
}
void FTPClientSession::remove(const std::string& path)
{
std::string response;
int status = sendCommand("DELE", path, response);
if (!isPositiveCompletion(status))
throw FTPException(std::string("Cannot remove " + path), response, status);
}
void FTPClientSession::createDirectory(const std::string& path)
{
std::string response;
int status = sendCommand("MKD", path, response);
if (!isPositiveCompletion(status))
throw FTPException(std::string("Cannot create directory ") + path, response, status);
}
void FTPClientSession::removeDirectory(const std::string& path)
{
std::string response;
int status = sendCommand("RMD", path, response);
if (!isPositiveCompletion(status))
throw FTPException(std::string("Cannot remove directory ") + path, response, status);
}
std::istream& FTPClientSession::beginDownload(const std::string& path)
{
if (!isOpen())
throw FTPException("Connection is closed.");
delete _pDataStream;
_pDataStream = 0;
_pDataStream = new SocketStream(establishDataConnection("RETR", path));
return *_pDataStream;
}
void FTPClientSession::endDownload()
{
endTransfer();
}
std::ostream& FTPClientSession::beginUpload(const std::string& path)
{
if (!isOpen())
throw FTPException("Connection is closed.");
delete _pDataStream;
_pDataStream = 0;
_pDataStream = new SocketStream(establishDataConnection("STOR", path));
return *_pDataStream;
}
void FTPClientSession::endUpload()
{
endTransfer();
}
std::istream& FTPClientSession::beginList(const std::string& path, bool extended)
{
if (!isOpen())
throw FTPException("Connection is closed.");
delete _pDataStream;
_pDataStream = 0;
_pDataStream = new SocketStream(establishDataConnection(extended ? "LIST" : "NLST", path));
return *_pDataStream;
}
void FTPClientSession::endList()
{
endTransfer();
}
void FTPClientSession::abort()
{
if (!isOpen())
throw FTPException("Connection is closed.");
_pControlSocket->sendByte(DialogSocket::TELNET_IP);
_pControlSocket->synch();
std::string response;
int status = sendCommand("ABOR", response);
if (status == 426)
status = _pControlSocket->receiveStatusMessage(response);
if (status != 226)
throw FTPException("Cannot abort transfer", response, status);
}
int FTPClientSession::sendCommand(const std::string& command, std::string& response)
{
if (!isOpen())
throw FTPException("Connection is closed.");
_pControlSocket->sendMessage(command);
return _pControlSocket->receiveStatusMessage(response);
}
int FTPClientSession::sendCommand(const std::string& command, const std::string& arg, std::string& response)
{
if (!isOpen())
throw FTPException("Connection is closed.");
_pControlSocket->sendMessage(command, arg);
return _pControlSocket->receiveStatusMessage(response);
}
std::string FTPClientSession::extractPath(const std::string& response)
{
std::string path;
std::string::const_iterator it = response.begin();
std::string::const_iterator end = response.end();
while (it != end && *it != '"') ++it;
if (it != end)
{
++it;
while (it != end)
{
if (*it == '"')
{
++it;
if (it == end || *it != '"') break;
}
path += *it++;
}
}
return path;
}
StreamSocket FTPClientSession::establishDataConnection(const std::string& command, const std::string& arg)
{
if (_passiveMode)
return passiveDataConnection(command, arg);
else
return activeDataConnection(command, arg);
}
StreamSocket FTPClientSession::activeDataConnection(const std::string& command, const std::string& arg)
{
if (!isOpen())
throw FTPException("Connection is closed.");
ServerSocket server(SocketAddress(_pControlSocket->address().host(), 0));
sendPortCommand(server.address());
std::string response;
int status = sendCommand(command, arg, response);
if (!isPositivePreliminary(status))
throw FTPException(command + " command failed", response, status);
if (server.poll(_timeout, Socket::SELECT_READ))
return server.acceptConnection();
else
throw FTPException("The server has not initiated a data connection");
}
StreamSocket FTPClientSession::passiveDataConnection(const std::string& command, const std::string& arg)
{
SocketAddress sa(sendPassiveCommand());
StreamSocket sock;
sock.connect(sa, _timeout);
sock.setReceiveTimeout(_timeout);
sock.setSendTimeout(_timeout);
std::string response;
int status = sendCommand(command, arg, response);
if (!isPositivePreliminary(status))
throw FTPException(command + " command failed", response, status);
return sock;
}
void FTPClientSession::sendPortCommand(const SocketAddress& addr)
{
if (_supports1738)
{
if (sendEPRT(addr))
return;
else
_supports1738 = false;
}
sendPORT(addr);
}
SocketAddress FTPClientSession::sendPassiveCommand()
{
SocketAddress addr;
if (_supports1738)
{
if (sendEPSV(addr))
return addr;
else
_supports1738 = false;
}
sendPASV(addr);
return addr;
}
bool FTPClientSession::sendEPRT(const SocketAddress& addr)
{
std::string arg("|");
arg += addr.af() == AF_INET ? '1' : '2';
arg += '|';
arg += addr.host().toString();
arg += '|';
arg += NumberFormatter::format(addr.port());
arg += '|';
std::string response;
int status = sendCommand("EPRT", arg, response);
if (isPositiveCompletion(status))
return true;
else if (isPermanentNegative(status))
return false;
else
throw FTPException("EPRT command failed", response, status);
}
void FTPClientSession::sendPORT(const SocketAddress& addr)
{
std::string arg(addr.host().toString());
for (auto& ch: arg)
{
if (ch == '.') ch = ',';
}
arg += ',';
Poco::UInt16 port = addr.port();
arg += NumberFormatter::format(port/256);
arg += ',';
arg += NumberFormatter::format(port % 256);
std::string response;
int status = sendCommand("PORT", arg, response);
if (!isPositiveCompletion(status))
throw FTPException("PORT command failed", response, status);
}
bool FTPClientSession::sendEPSV(SocketAddress& addr)
{
std::string response;
int status = sendCommand("EPSV", response);
if (isPositiveCompletion(status))
{
parseExtAddress(response, addr);
return true;
}
else if (isPermanentNegative(status))
{
return false;
}
else throw FTPException("EPSV command failed", response, status);
}
void FTPClientSession::sendPASV(SocketAddress& addr)
{
std::string response;
int status = sendCommand("PASV", response);
if (!isPositiveCompletion(status))
throw FTPException("PASV command failed", response, status);
parseAddress(response, addr);
}
void FTPClientSession::parseAddress(const std::string& str, SocketAddress& addr)
{
std::string::const_iterator it = str.begin();
std::string::const_iterator end = str.end();
while (it != end && *it != '(') ++it;
if (it != end) ++it;
std::string host;
while (it != end && Poco::Ascii::isDigit(*it)) host += *it++;
if (it != end && *it == ',') { host += '.'; ++it; }
while (it != end && Poco::Ascii::isDigit(*it)) host += *it++;
if (it != end && *it == ',') { host += '.'; ++it; }
while (it != end && Poco::Ascii::isDigit(*it)) host += *it++;
if (it != end && *it == ',') { host += '.'; ++it; }
while (it != end && Poco::Ascii::isDigit(*it)) host += *it++;
if (it != end && *it == ',') ++it;
Poco::UInt16 portHi = 0;
while (it != end && Poco::Ascii::isDigit(*it)) { portHi *= 10; portHi += *it++ - '0'; }
if (it != end && *it == ',') ++it;
Poco::UInt16 portLo = 0;
while (it != end && Poco::Ascii::isDigit(*it)) { portLo *= 10; portLo += *it++ - '0'; }
addr = SocketAddress(host, portHi*256 + portLo);
}
void FTPClientSession::parseExtAddress(const std::string& str, SocketAddress& addr)
{
std::string::const_iterator it = str.begin();
std::string::const_iterator end = str.end();
while (it != end && *it != '(') ++it;
if (it != end) ++it;
char delim = '|';
if (it != end) delim = *it++;
if (it != end && *it == delim) ++it;
if (it != end && *it == delim) ++it;
Poco::UInt16 port = 0;
while (it != end && Poco::Ascii::isDigit(*it)) { port *= 10; port += *it++ - '0'; }
addr = SocketAddress(_pControlSocket->peerAddress().host(), port);
}
void FTPClientSession::endTransfer()
{
if (_pDataStream)
{
delete _pDataStream;
_pDataStream = 0;
std::string response;
int status = _pControlSocket->receiveStatusMessage(response);
if (!isPositiveCompletion(status))
throw FTPException("Data transfer failed", response, status);
}
}
} } // namespace Poco::Net
+243
View File
@@ -0,0 +1,243 @@
//
// FTPStreamFactory.cpp
//
// Library: Net
// Package: FTP
// Module: FTPStreamFactory
//
// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/FTPStreamFactory.h"
#include "Poco/Net/FTPClientSession.h"
#include "Poco/Net/NetException.h"
#include "Poco/URI.h"
#include "Poco/URIStreamOpener.h"
#include "Poco/UnbufferedStreamBuf.h"
#include "Poco/Path.h"
using Poco::URIStreamFactory;
using Poco::URI;
using Poco::URIStreamOpener;
using Poco::UnbufferedStreamBuf;
using Poco::Path;
namespace Poco {
namespace Net {
class FTPStreamBuf: public UnbufferedStreamBuf
{
public:
FTPStreamBuf(std::istream& istr):
_istr(istr)
{
// make sure exceptions from underlying string propagate
_istr.exceptions(std::ios::badbit);
}
~FTPStreamBuf()
{
}
private:
int readFromDevice()
{
return _istr.get();
}
std::istream& _istr;
};
class FTPIOS: public virtual std::ios
{
public:
FTPIOS(std::istream& istr):
_buf(istr)
{
poco_ios_init(&_buf);
}
~FTPIOS()
{
}
FTPStreamBuf* rdbuf()
{
return &_buf;
}
protected:
FTPStreamBuf _buf;
};
class FTPStream: public FTPIOS, public std::istream
{
public:
FTPStream(std::istream& istr, FTPClientSession* pSession):
FTPIOS(istr),
std::istream(&_buf),
_pSession(pSession)
{
}
~FTPStream()
{
delete _pSession;
}
private:
FTPClientSession* _pSession;
};
FTPPasswordProvider::FTPPasswordProvider()
{
}
FTPPasswordProvider::~FTPPasswordProvider()
{
}
std::string FTPStreamFactory::_anonymousPassword("poco@localhost");
FTPPasswordProvider* FTPStreamFactory::_pPasswordProvider(0);
FTPStreamFactory::FTPStreamFactory()
{
}
FTPStreamFactory::~FTPStreamFactory()
{
}
std::istream* FTPStreamFactory::open(const URI& uri)
{
poco_assert (uri.getScheme() == "ftp");
FTPClientSession* pSession = new FTPClientSession(uri.getHost(), uri.getPort());
try
{
std::string username;
std::string password;
getUserInfo(uri, username, password);
std::string path;
char type;
getPathAndType(uri, path, type);
pSession->login(username, password);
if (type == 'a')
pSession->setFileType(FTPClientSession::TYPE_TEXT);
Path p(path, Path::PATH_UNIX);
p.makeFile();
for (int i = 0; i < p.depth(); ++i)
pSession->setWorkingDirectory(p[i]);
std::string file(p.getFileName());
std::istream& istr = (type == 'd' ? pSession->beginList(file) : pSession->beginDownload(file));
return new FTPStream(istr, pSession);
}
catch (...)
{
delete pSession;
throw;
}
}
void FTPStreamFactory::setAnonymousPassword(const std::string& password)
{
_anonymousPassword = password;
}
const std::string& FTPStreamFactory::getAnonymousPassword()
{
return _anonymousPassword;
}
void FTPStreamFactory::setPasswordProvider(FTPPasswordProvider* pProvider)
{
_pPasswordProvider = pProvider;
}
FTPPasswordProvider* FTPStreamFactory::getPasswordProvider()
{
return _pPasswordProvider;
}
void FTPStreamFactory::splitUserInfo(const std::string& userInfo, std::string& username, std::string& password)
{
std::string::size_type pos = userInfo.find(':');
if (pos != std::string::npos)
{
username.assign(userInfo, 0, pos++);
password.assign(userInfo, pos, userInfo.size() - pos);
}
else username = userInfo;
}
void FTPStreamFactory::getUserInfo(const URI& uri, std::string& username, std::string& password)
{
splitUserInfo(uri.getUserInfo(), username, password);
if (username.empty())
{
username = "anonymous";
password = _anonymousPassword;
}
else if (password.empty())
{
if (_pPasswordProvider)
password = _pPasswordProvider->password(username, uri.getHost());
else
throw FTPException(std::string("Password required for ") + username + "@" + uri.getHost());
}
}
void FTPStreamFactory::getPathAndType(const Poco::URI& uri, std::string& path, char& type)
{
path = uri.getPath();
type = 'i';
std::string::size_type pos = path.rfind(';');
if (pos != std::string::npos)
{
if (path.length() == pos + 7 && path.compare(pos + 1, 5, "type=") == 0)
{
type = path[pos + 6];
path.resize(pos);
}
}
}
void FTPStreamFactory::registerFactory()
{
URIStreamOpener::defaultOpener().registerStreamFactory("ftp", new FTPStreamFactory);
}
void FTPStreamFactory::unregisterFactory()
{
URIStreamOpener::defaultOpener().unregisterStreamFactory("ftp");
}
} } // namespace Poco::Net
+87
View File
@@ -0,0 +1,87 @@
//
// FilePartSource.cpp
//
// Library: Net
// Package: Messages
// Module: FilePartSource
//
// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/FilePartSource.h"
#include "Poco/Path.h"
#include "Poco/File.h"
#include "Poco/Exception.h"
using Poco::Path;
using Poco::OpenFileException;
namespace Poco {
namespace Net {
FilePartSource::FilePartSource(const std::string& path):
_path(path), _istr(path)
{
Path p(path);
_filename = p.getFileName();
if (!_istr.good())
throw OpenFileException(path);
}
FilePartSource::FilePartSource(const std::string& path, const std::string& mediaType):
PartSource(mediaType),
_path(path),
_istr(path)
{
Path p(path);
_filename = p.getFileName();
if (!_istr.good())
throw OpenFileException(path);
}
FilePartSource::FilePartSource(const std::string& path, const std::string& filename, const std::string& mediaType):
PartSource(mediaType),
_path(path),
_filename(filename),
_istr(path)
{
Path p(path);
if (!_istr.good())
throw OpenFileException(path);
}
FilePartSource::~FilePartSource()
{
}
std::istream& FilePartSource::stream()
{
return _istr;
}
const std::string& FilePartSource::filename() const
{
return _filename;
}
std::streamsize FilePartSource::getContentLength() const
{
Poco::File p(_path);
return static_cast<std::streamsize>(p.getSize());
}
} } // namespace Poco::Net
+468
View File
@@ -0,0 +1,468 @@
//
// HTMLForm.cpp
//
// Library: Net
// Package: HTML
// Module: HTMLForm
//
// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/HTMLForm.h"
#include "Poco/Net/HTTPRequest.h"
#include "Poco/Net/PartSource.h"
#include "Poco/Net/PartHandler.h"
#include "Poco/Net/MultipartWriter.h"
#include "Poco/Net/MultipartReader.h"
#include "Poco/Net/NullPartHandler.h"
#include "Poco/Net/NetException.h"
#include "Poco/NullStream.h"
#include "Poco/CountingStream.h"
#include "Poco/StreamCopier.h"
#include "Poco/URI.h"
#include "Poco/String.h"
#include "Poco/CountingStream.h"
#include "Poco/UTF8String.h"
#include <sstream>
using Poco::NullInputStream;
using Poco::StreamCopier;
using Poco::SyntaxException;
using Poco::URI;
using Poco::icompare;
namespace Poco {
namespace Net {
const std::string HTMLForm::ENCODING_URL = "application/x-www-form-urlencoded";
const std::string HTMLForm::ENCODING_MULTIPART = "multipart/form-data";
const int HTMLForm::UNKNOWN_CONTENT_LENGTH = -1;
class HTMLFormCountingOutputStream: public CountingOutputStream
{
public:
HTMLFormCountingOutputStream():
_valid(true)
{
}
bool isValid() const
{
return _valid;
}
void setValid(bool v)
{
_valid = v;
}
private:
bool _valid;
};
HTMLForm::HTMLForm():
_fieldLimit(DFL_FIELD_LIMIT),
_valueLengthLimit(DFL_MAX_VALUE_LENGTH),
_encoding(ENCODING_URL)
{
}
HTMLForm::HTMLForm(const std::string& encoding):
_fieldLimit(DFL_FIELD_LIMIT),
_valueLengthLimit(DFL_MAX_VALUE_LENGTH),
_encoding(encoding)
{
}
HTMLForm::HTMLForm(const HTTPRequest& request, std::istream& requestBody, PartHandler& handler):
_fieldLimit(DFL_FIELD_LIMIT),
_valueLengthLimit(DFL_MAX_VALUE_LENGTH)
{
load(request, requestBody, handler);
}
HTMLForm::HTMLForm(const HTTPRequest& request, std::istream& requestBody):
_fieldLimit(DFL_FIELD_LIMIT),
_valueLengthLimit(DFL_MAX_VALUE_LENGTH)
{
load(request, requestBody);
}
HTMLForm::HTMLForm(const HTTPRequest& request):
_fieldLimit(DFL_FIELD_LIMIT),
_valueLengthLimit(DFL_MAX_VALUE_LENGTH)
{
load(request);
}
HTMLForm::~HTMLForm()
{
for (auto& part: _parts)
{
delete part.pSource;
}
}
void HTMLForm::setEncoding(const std::string& encoding)
{
_encoding = encoding;
}
void HTMLForm::addPart(const std::string& name, PartSource* pSource)
{
poco_check_ptr (pSource);
Part part;
part.name = name;
part.pSource = pSource;
_parts.push_back(part);
}
void HTMLForm::load(const HTTPRequest& request, std::istream& requestBody, PartHandler& handler)
{
clear();
URI uri(request.getURI());
const std::string& query = uri.getRawQuery();
if (!query.empty())
{
std::istringstream istr(query);
readUrl(istr);
}
if (request.getMethod() == HTTPRequest::HTTP_POST || request.getMethod() == HTTPRequest::HTTP_PUT)
{
std::string mediaType;
NameValueCollection params;
MessageHeader::splitParameters(request.getContentType(), mediaType, params);
_encoding = mediaType;
if (_encoding == ENCODING_MULTIPART)
{
_boundary = params["boundary"];
readMultipart(requestBody, handler);
}
else
{
readUrl(requestBody);
}
}
}
void HTMLForm::load(const HTTPRequest& request, std::istream& requestBody)
{
NullPartHandler nah;
load(request, requestBody, nah);
}
void HTMLForm::load(const HTTPRequest& request)
{
NullPartHandler nah;
NullInputStream nis;
load(request, nis, nah);
}
void HTMLForm::read(std::istream& istr, PartHandler& handler)
{
if (_encoding == ENCODING_URL)
readUrl(istr);
else
readMultipart(istr, handler);
}
void HTMLForm::read(std::istream& istr)
{
readUrl(istr);
}
void HTMLForm::read(const std::string& queryString)
{
std::istringstream istr(queryString);
readUrl(istr);
}
void HTMLForm::prepareSubmit(HTTPRequest& request, int options)
{
if (request.getMethod() == HTTPRequest::HTTP_POST || request.getMethod() == HTTPRequest::HTTP_PUT)
{
if (_encoding == ENCODING_URL)
{
request.setContentType(_encoding);
request.setChunkedTransferEncoding(false);
Poco::CountingOutputStream ostr;
writeUrl(ostr);
request.setContentLength(ostr.chars());
}
else
{
_boundary = MultipartWriter::createBoundary();
std::string ct(_encoding);
ct.append("; boundary=\"");
ct.append(_boundary);
ct.append("\"");
request.setContentType(ct);
}
if (request.getVersion() == HTTPMessage::HTTP_1_0)
{
request.setKeepAlive(false);
request.setChunkedTransferEncoding(false);
}
else if (_encoding != ENCODING_URL && (options & OPT_USE_CONTENT_LENGTH) == 0)
{
request.setChunkedTransferEncoding(true);
}
if (!request.getChunkedTransferEncoding() && !request.hasContentLength())
{
request.setContentLength(calculateContentLength());
}
}
else
{
std::string uri = request.getURI();
std::ostringstream ostr;
writeUrl(ostr);
uri.append("?");
uri.append(ostr.str());
request.setURI(uri);
}
}
std::streamsize HTMLForm::calculateContentLength()
{
if (_encoding == ENCODING_MULTIPART && _boundary.empty())
throw HTMLFormException("Form must be prepared");
HTMLFormCountingOutputStream c;
write(c);
if (c.isValid())
return c.chars();
else
return UNKNOWN_CONTENT_LENGTH;
}
void HTMLForm::write(std::ostream& ostr, const std::string& boundary)
{
if (_encoding == ENCODING_URL)
{
writeUrl(ostr);
}
else
{
_boundary = boundary;
writeMultipart(ostr);
}
}
void HTMLForm::write(std::ostream& ostr)
{
if (_encoding == ENCODING_URL)
writeUrl(ostr);
else
writeMultipart(ostr);
}
void HTMLForm::readUrl(std::istream& istr)
{
static const int eof = std::char_traits<char>::eof();
int fields = 0;
int ch = istr.get();
bool isFirst = true;
while (ch != eof)
{
if (_fieldLimit > 0 && fields == _fieldLimit)
throw HTMLFormException("Too many form fields");
std::string name;
std::string value;
while (ch != eof && ch != '=' && ch != '&')
{
if (ch == '+') ch = ' ';
if (name.size() < MAX_NAME_LENGTH)
name += (char) ch;
else
throw HTMLFormException("Field name too long");
ch = istr.get();
}
if (ch == '=')
{
ch = istr.get();
while (ch != eof && ch != '&')
{
if (ch == '+') ch = ' ';
if (value.size() < _valueLengthLimit)
value += (char) ch;
else
throw HTMLFormException("Field value too long");
ch = istr.get();
}
}
// remove UTF-8 byte order mark from first name, if present
if (isFirst)
{
UTF8::removeBOM(name);
}
std::string decodedName;
std::string decodedValue;
URI::decode(name, decodedName);
URI::decode(value, decodedValue);
add(decodedName, decodedValue);
++fields;
if (ch == '&') ch = istr.get();
isFirst = false;
}
}
void HTMLForm::readMultipart(std::istream& istr, PartHandler& handler)
{
static const int eof = std::char_traits<char>::eof();
int fields = 0;
MultipartReader reader(istr, _boundary);
while (reader.hasNextPart())
{
if (_fieldLimit > 0 && fields == _fieldLimit)
throw HTMLFormException("Too many form fields");
MessageHeader header;
reader.nextPart(header);
std::string disp;
NameValueCollection params;
if (header.has("Content-Disposition"))
{
std::string cd = header.get("Content-Disposition");
MessageHeader::splitParameters(cd, disp, params);
}
if (params.has("filename"))
{
handler.handlePart(header, reader.stream());
// Ensure that the complete part has been read.
while (reader.stream().good()) reader.stream().get();
}
else
{
std::string name = params["name"];
std::string value;
std::istream& istr = reader.stream();
int ch = istr.get();
while (ch != eof)
{
if (value.size() < _valueLengthLimit)
value += (char) ch;
else
throw HTMLFormException("Field value too long");
ch = istr.get();
}
add(name, value);
}
++fields;
}
}
void HTMLForm::writeUrl(std::ostream& ostr)
{
for (auto it = begin(); it != end(); ++it)
{
if (it != begin()) ostr << "&";
std::string name;
URI::encode(it->first, "!?#/'\",;:$&()[]*+=@", name);
std::string value;
URI::encode(it->second, "!?#/'\",;:$&()[]*+=@", value);
ostr << name << "=" << value;
}
}
void HTMLForm::writeMultipart(std::ostream& ostr)
{
HTMLFormCountingOutputStream* pCountingOutputStream(dynamic_cast<HTMLFormCountingOutputStream*>(&ostr));
MultipartWriter writer(ostr, _boundary);
for (auto it = begin(); it != end(); ++it)
{
MessageHeader header;
std::string disp("form-data; name=\"");
disp.append(it->first);
disp.append("\"");
header.set("Content-Disposition", disp);
writer.nextPart(header);
ostr << it->second;
}
for (const auto& part: _parts)
{
MessageHeader header(part.pSource->headers());
std::string disp("form-data; name=\"");
disp.append(part.name);
disp.append("\"");
std::string filename = part.pSource->filename();
if (!filename.empty())
{
disp.append("; filename=\"");
disp.append(filename);
disp.append("\"");
}
header.set("Content-Disposition", disp);
header.set("Content-Type", part.pSource->mediaType());
writer.nextPart(header);
if (pCountingOutputStream)
{
// count only, don't move stream position
std::streamsize partlen = part.pSource->getContentLength();
if (partlen != PartSource::UNKNOWN_CONTENT_LENGTH)
pCountingOutputStream->addChars(partlen);
else
pCountingOutputStream->setValid(false);
}
else
{
StreamCopier::copyStream(part.pSource->stream(), ostr);
}
}
writer.close();
_boundary = writer.boundary();
}
void HTMLForm::setFieldLimit(int limit)
{
poco_assert (limit >= 0);
_fieldLimit = limit;
}
void HTMLForm::setValueLengthLimit(int limit)
{
poco_assert (limit >= 0);
_valueLengthLimit = limit;
}
} } // namespace Poco::Net
+328
View File
@@ -0,0 +1,328 @@
//
// HTTPAuthenticationParams.cpp
//
// Library: Net
// Package: HTTP
// Module: HTTPAuthenticationParams
//
// Copyright (c) 2011, Anton V. Yabchinskiy (arn at bestmx dot ru).
// Copyright (c) 2012, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/HTTPAuthenticationParams.h"
#include "Poco/Net/HTTPRequest.h"
#include "Poco/Net/HTTPResponse.h"
#include "Poco/Net/NetException.h"
#include "Poco/String.h"
#include "Poco/Ascii.h"
#include "Poco/Exception.h"
using Poco::icompare;
using Poco::Ascii;
namespace
{
bool mustBeQuoted(const std::string& name)
{
return
icompare(name, "cnonce") == 0 ||
icompare(name, "domain") == 0 ||
icompare(name, "nonce") == 0 ||
icompare(name, "opaque") == 0 ||
icompare(name, "qop") == 0 ||
icompare(name, "realm") == 0 ||
icompare(name, "response") == 0 ||
icompare(name, "uri") == 0 ||
icompare(name, "username") == 0;
}
void formatParameter(std::string& result, const std::string& name, const std::string& value)
{
result += name;
result += '=';
if (mustBeQuoted(name))
{
result += '"';
result += value;
result += '"';
}
else
{
result += value;
}
}
}
namespace Poco {
namespace Net {
const std::string HTTPAuthenticationParams::REALM("realm");
const std::string HTTPAuthenticationParams::NTLM("NTLM");
const std::string HTTPAuthenticationParams::WWW_AUTHENTICATE("WWW-Authenticate");
const std::string HTTPAuthenticationParams::PROXY_AUTHENTICATE("Proxy-Authenticate");
HTTPAuthenticationParams::HTTPAuthenticationParams()
{
}
HTTPAuthenticationParams::HTTPAuthenticationParams(const std::string& authInfo)
{
fromAuthInfo(authInfo);
}
HTTPAuthenticationParams::HTTPAuthenticationParams(const HTTPRequest& request)
{
fromRequest(request);
}
HTTPAuthenticationParams::HTTPAuthenticationParams(const HTTPResponse& response, const std::string& header)
{
fromResponse(response, header);
}
HTTPAuthenticationParams::~HTTPAuthenticationParams()
{
}
HTTPAuthenticationParams& HTTPAuthenticationParams::operator = (const HTTPAuthenticationParams& authParams)
{
NameValueCollection::operator = (authParams);
return *this;
}
void HTTPAuthenticationParams::fromAuthInfo(const std::string& authInfo)
{
parse(authInfo.begin(), authInfo.end());
}
void HTTPAuthenticationParams::fromRequest(const HTTPRequest& request)
{
std::string scheme;
std::string authInfo;
request.getCredentials(scheme, authInfo);
if (icompare(scheme, "Digest") != 0)
throw InvalidArgumentException("Could not parse non-Digest authentication information", scheme);
fromAuthInfo(authInfo);
}
void HTTPAuthenticationParams::fromResponse(const HTTPResponse& response, const std::string& header)
{
NameValueCollection::ConstIterator it = response.find(header);
if (it == response.end())
throw NotAuthenticatedException("HTTP response has no authentication header");
bool found = false;
while (!found && it != response.end() && icompare(it->first, header) == 0)
{
const std::string& headerValue = it->second;
if (icompare(headerValue, 0, 6, "Basic ") == 0)
{
parse(headerValue.begin() + 6, headerValue.end());
found = true;
}
else if (icompare(headerValue, 0, 7, "Digest ") == 0)
{
parse(headerValue.begin() + 7, headerValue.end());
found = true;
}
else if (icompare(headerValue, 0, 5, "NTLM ") == 0)
{
set(NTLM, headerValue.substr(5));
found = true;
}
++it;
}
if (!found) throw NotAuthenticatedException("No Basic, Digest or NTLM authentication header found");
}
const std::string& HTTPAuthenticationParams::getRealm() const
{
return get(REALM);
}
void HTTPAuthenticationParams::setRealm(const std::string& realm)
{
set(REALM, realm);
}
std::string HTTPAuthenticationParams::toString() const
{
std::string result;
if (size() == 1 && find(NTLM) != end())
{
result = get(NTLM);
}
else
{
ConstIterator iter = begin();
if (iter != end())
{
formatParameter(result, iter->first, iter->second);
++iter;
}
for (; iter != end(); ++iter)
{
result.append(", ");
formatParameter(result, iter->first, iter->second);
}
}
return result;
}
void HTTPAuthenticationParams::parse(std::string::const_iterator first, std::string::const_iterator last)
{
enum State
{
STATE_INITIAL = 0x0100,
STATE_FINAL = 0x0200,
STATE_SPACE = STATE_INITIAL | 0,
STATE_TOKEN = 1,
STATE_EQUALS = 2,
STATE_VALUE = STATE_FINAL | 3,
STATE_VALUE_QUOTED = 4,
STATE_VALUE_ESCAPE = 5,
STATE_COMMA = STATE_FINAL | 6
};
int state = STATE_SPACE;
std::string token;
std::string value;
for (std::string::const_iterator it = first; it != last; ++it)
{
switch (state)
{
case STATE_SPACE:
if (Ascii::isAlphaNumeric(*it) || *it == '_' || *it == '-')
{
token += *it;
state = STATE_TOKEN;
}
else if (Ascii::isSpace(*it))
{
// Skip
}
else throw SyntaxException("Invalid authentication information");
break;
case STATE_TOKEN:
if (*it == '=')
{
state = STATE_EQUALS;
}
else if (Ascii::isAlphaNumeric(*it) || *it == '_' || *it == '-')
{
token += *it;
}
else throw SyntaxException("Invalid authentication information");
break;
case STATE_EQUALS:
if (Ascii::isAlphaNumeric(*it) || *it == '_')
{
value += *it;
state = STATE_VALUE;
}
else if (*it == '"')
{
state = STATE_VALUE_QUOTED;
}
else throw SyntaxException("Invalid authentication information");
break;
case STATE_VALUE_QUOTED:
if (*it == '\\')
{
state = STATE_VALUE_ESCAPE;
}
else if (*it == '"')
{
add(token, value);
token.clear();
value.clear();
state = STATE_COMMA;
}
else
{
value += *it;
}
break;
case STATE_VALUE_ESCAPE:
value += *it;
state = STATE_VALUE_QUOTED;
break;
case STATE_VALUE:
if (Ascii::isSpace(*it))
{
add(token, value);
token.clear();
value.clear();
state = STATE_COMMA;
}
else if (*it == ',')
{
add(token, value);
token.clear();
value.clear();
state = STATE_SPACE;
}
else
{
value += *it;
}
break;
case STATE_COMMA:
if (*it == ',')
{
state = STATE_SPACE;
}
else if (Ascii::isSpace(*it))
{
// Skip
}
else throw SyntaxException("Invalid authentication information");
break;
}
}
if (state == STATE_VALUE)
add(token, value);
if (!(state & STATE_FINAL))
throw SyntaxException("Invalid authentication information");
}
} } // namespace Poco::Net
+134
View File
@@ -0,0 +1,134 @@
//
// HTTPBasicCredentials.cpp
//
// Library: Net
// Package: HTTP
// Module: HTTPBasicCredentials
//
// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/HTTPBasicCredentials.h"
#include "Poco/Net/HTTPRequest.h"
#include "Poco/Net/NetException.h"
#include "Poco/Base64Encoder.h"
#include "Poco/Base64Decoder.h"
#include "Poco/String.h"
#include <sstream>
using Poco::Base64Decoder;
using Poco::Base64Encoder;
using Poco::icompare;
namespace Poco {
namespace Net {
const std::string HTTPBasicCredentials::SCHEME = "Basic";
HTTPBasicCredentials::HTTPBasicCredentials()
{
}
HTTPBasicCredentials::HTTPBasicCredentials(const std::string& username, const std::string& password):
_username(username),
_password(password)
{
}
HTTPBasicCredentials::HTTPBasicCredentials(const HTTPRequest& request)
{
std::string scheme;
std::string authInfo;
request.getCredentials(scheme, authInfo);
if (icompare(scheme, SCHEME) == 0)
{
parseAuthInfo(authInfo);
}
else throw NotAuthenticatedException("Basic authentication expected");
}
HTTPBasicCredentials::HTTPBasicCredentials(const std::string& authInfo)
{
parseAuthInfo(authInfo);
}
HTTPBasicCredentials::~HTTPBasicCredentials()
{
}
void HTTPBasicCredentials::clear()
{
_username.clear();
_password.clear();
}
void HTTPBasicCredentials::setUsername(const std::string& username)
{
_username = username;
}
void HTTPBasicCredentials::setPassword(const std::string& password)
{
_password = password;
}
void HTTPBasicCredentials::authenticate(HTTPRequest& request) const
{
std::ostringstream ostr;
Base64Encoder encoder(ostr);
encoder.rdbuf()->setLineLength(0);
encoder << _username << ":" << _password;
encoder.close();
request.setCredentials(SCHEME, ostr.str());
}
void HTTPBasicCredentials::proxyAuthenticate(HTTPRequest& request) const
{
std::ostringstream ostr;
Base64Encoder encoder(ostr);
encoder.rdbuf()->setLineLength(0);
encoder << _username << ":" << _password;
encoder.close();
request.setProxyCredentials(SCHEME, ostr.str());
}
void HTTPBasicCredentials::parseAuthInfo(const std::string& authInfo)
{
static const int eof = std::char_traits<char>::eof();
std::istringstream istr(authInfo);
Base64Decoder decoder(istr);
int ch = decoder.get();
while (ch != eof && ch != ':')
{
_username += (char) ch;
ch = decoder.get();
}
if (ch == ':') ch = decoder.get();
while (ch != eof)
{
_password += (char) ch;
ch = decoder.get();
}
}
} } // namespace Poco::Net
+44
View File
@@ -0,0 +1,44 @@
//
// HTTPBufferAllocator.cpp
//
// Library: Net
// Package: HTTP
// Module: HTTPBufferAllocator
//
// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/HTTPBufferAllocator.h"
using Poco::MemoryPool;
namespace Poco {
namespace Net {
MemoryPool HTTPBufferAllocator::_pool(HTTPBufferAllocator::BUFFER_SIZE, 16);
char* HTTPBufferAllocator::allocate(std::streamsize size)
{
poco_assert_dbg (size == BUFFER_SIZE);
return reinterpret_cast<char*>(_pool.get());
}
void HTTPBufferAllocator::deallocate(char* ptr, std::streamsize size)
{
poco_assert_dbg (size == BUFFER_SIZE);
_pool.release(ptr);
}
} } // namespace Poco::Net
+213
View File
@@ -0,0 +1,213 @@
//
// HTTPChunkedStream.cpp
//
// Library: Net
// Package: HTTP
// Module: HTTPChunkedStream
//
// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/HTTPChunkedStream.h"
#include "Poco/Net/HTTPSession.h"
#include "Poco/NumberFormatter.h"
#include "Poco/NumberParser.h"
#include "Poco/Ascii.h"
using Poco::NumberFormatter;
using Poco::NumberParser;
namespace Poco {
namespace Net {
//
// HTTPChunkedStreamBuf
//
HTTPChunkedStreamBuf::HTTPChunkedStreamBuf(HTTPSession& session, openmode mode):
HTTPBasicStreamBuf(HTTPBufferAllocator::BUFFER_SIZE, mode),
_session(session),
_mode(mode),
_chunk(0)
{
}
HTTPChunkedStreamBuf::~HTTPChunkedStreamBuf()
{
}
void HTTPChunkedStreamBuf::close()
{
if (_mode & std::ios::out)
{
sync();
_session.write("0\r\n\r\n", 5);
}
}
int HTTPChunkedStreamBuf::readFromDevice(char* buffer, std::streamsize length)
{
static const int eof = std::char_traits<char>::eof();
if (_chunk == 0)
{
int ch = _session.get();
while (Poco::Ascii::isSpace(ch)) ch = _session.get();
std::string chunkLen;
while (Poco::Ascii::isHexDigit(ch) && chunkLen.size() < 8) { chunkLen += (char) ch; ch = _session.get(); }
if (ch != eof && !(Poco::Ascii::isSpace(ch) || ch == ';')) return eof;
while (ch != eof && ch != '\n') ch = _session.get();
unsigned chunk;
if (NumberParser::tryParseHex(chunkLen, chunk))
_chunk = (std::streamsize) chunk;
else
return eof;
}
if (_chunk > 0)
{
if (length > _chunk) length = _chunk;
int n = _session.read(buffer, length);
if (n > 0) _chunk -= n;
return n;
}
else
{
int ch = _session.get();
while (ch != eof && ch != '\n') ch = _session.get();
return 0;
}
}
int HTTPChunkedStreamBuf::writeToDevice(const char* buffer, std::streamsize length)
{
_chunkBuffer.clear();
NumberFormatter::appendHex(_chunkBuffer, length);
_chunkBuffer.append("\r\n", 2);
_chunkBuffer.append(buffer, static_cast<std::string::size_type>(length));
_chunkBuffer.append("\r\n", 2);
_session.write(_chunkBuffer.data(), static_cast<std::streamsize>(_chunkBuffer.size()));
return static_cast<int>(length);
}
//
// HTTPChunkedIOS
//
HTTPChunkedIOS::HTTPChunkedIOS(HTTPSession& session, HTTPChunkedStreamBuf::openmode mode):
_buf(session, mode)
{
poco_ios_init(&_buf);
}
HTTPChunkedIOS::~HTTPChunkedIOS()
{
try
{
_buf.close();
}
catch (...)
{
}
}
HTTPChunkedStreamBuf* HTTPChunkedIOS::rdbuf()
{
return &_buf;
}
//
// HTTPChunkedInputStream
//
Poco::MemoryPool HTTPChunkedInputStream::_pool(sizeof(HTTPChunkedInputStream));
HTTPChunkedInputStream::HTTPChunkedInputStream(HTTPSession& session):
HTTPChunkedIOS(session, std::ios::in),
std::istream(&_buf)
{
}
HTTPChunkedInputStream::~HTTPChunkedInputStream()
{
}
void* HTTPChunkedInputStream::operator new(std::size_t size)
{
return _pool.get();
}
void HTTPChunkedInputStream::operator delete(void* ptr)
{
try
{
_pool.release(ptr);
}
catch (...)
{
poco_unexpected();
}
}
//
// HTTPChunkedOutputStream
//
Poco::MemoryPool HTTPChunkedOutputStream::_pool(sizeof(HTTPChunkedOutputStream));
HTTPChunkedOutputStream::HTTPChunkedOutputStream(HTTPSession& session):
HTTPChunkedIOS(session, std::ios::out),
std::ostream(&_buf)
{
}
HTTPChunkedOutputStream::~HTTPChunkedOutputStream()
{
}
void* HTTPChunkedOutputStream::operator new(std::size_t size)
{
return _pool.get();
}
void HTTPChunkedOutputStream::operator delete(void* ptr)
{
try
{
_pool.release(ptr);
}
catch (...)
{
poco_unexpected();
}
}
} } // namespace Poco::Net
+562
View File
@@ -0,0 +1,562 @@
//
// HTTPClientSession.cpp
//
// Library: Net
// Package: HTTPClient
// Module: HTTPClientSession
//
// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/HTTPClientSession.h"
#include "Poco/Net/HTTPRequest.h"
#include "Poco/Net/HTTPResponse.h"
#include "Poco/Net/HTTPHeaderStream.h"
#include "Poco/Net/HTTPStream.h"
#include "Poco/Net/HTTPFixedLengthStream.h"
#include "Poco/Net/HTTPChunkedStream.h"
#include "Poco/Net/HTTPCredentials.h"
#include "Poco/Net/NetException.h"
#include "Poco/NumberFormatter.h"
#include "Poco/CountingStream.h"
#include "Poco/RegularExpression.h"
#include <sstream>
using Poco::NumberFormatter;
using Poco::IllegalStateException;
namespace Poco {
namespace Net {
HTTPClientSession::ProxyConfig HTTPClientSession::_globalProxyConfig;
HTTPClientSession::HTTPClientSession():
_port(HTTPSession::HTTP_PORT),
_proxyConfig(_globalProxyConfig),
_keepAliveTimeout(DEFAULT_KEEP_ALIVE_TIMEOUT, 0),
_reconnect(false),
_mustReconnect(false),
_expectResponseBody(false),
_responseReceived(false),
_ntlmProxyAuthenticated(false)
{
}
HTTPClientSession::HTTPClientSession(const StreamSocket& socket):
HTTPSession(socket),
_port(HTTPSession::HTTP_PORT),
_proxyConfig(_globalProxyConfig),
_keepAliveTimeout(DEFAULT_KEEP_ALIVE_TIMEOUT, 0),
_reconnect(false),
_mustReconnect(false),
_expectResponseBody(false),
_responseReceived(false),
_ntlmProxyAuthenticated(false)
{
}
HTTPClientSession::HTTPClientSession(const SocketAddress& address):
_host(address.host().toString()),
_port(address.port()),
_proxyConfig(_globalProxyConfig),
_keepAliveTimeout(DEFAULT_KEEP_ALIVE_TIMEOUT, 0),
_reconnect(false),
_mustReconnect(false),
_expectResponseBody(false),
_responseReceived(false),
_ntlmProxyAuthenticated(false)
{
}
HTTPClientSession::HTTPClientSession(const std::string& host, Poco::UInt16 port):
_host(host),
_port(port),
_proxyConfig(_globalProxyConfig),
_keepAliveTimeout(DEFAULT_KEEP_ALIVE_TIMEOUT, 0),
_reconnect(false),
_mustReconnect(false),
_expectResponseBody(false),
_responseReceived(false),
_ntlmProxyAuthenticated(false)
{
}
HTTPClientSession::HTTPClientSession(const std::string& host, Poco::UInt16 port, const ProxyConfig& proxyConfig):
_host(host),
_port(port),
_proxyConfig(proxyConfig),
_keepAliveTimeout(DEFAULT_KEEP_ALIVE_TIMEOUT, 0),
_reconnect(false),
_mustReconnect(false),
_expectResponseBody(false),
_responseReceived(false),
_ntlmProxyAuthenticated(false)
{
}
HTTPClientSession::~HTTPClientSession()
{
}
void HTTPClientSession::setHost(const std::string& host)
{
if (!connected())
_host = host;
else
throw IllegalStateException("Cannot set the host for an already connected session");
}
void HTTPClientSession::setPort(Poco::UInt16 port)
{
if (!connected())
_port = port;
else
throw IllegalStateException("Cannot set the port number for an already connected session");
}
void HTTPClientSession::setProxy(const std::string& host, Poco::UInt16 port)
{
if (!connected())
{
_proxyConfig.host = host;
_proxyConfig.port = port;
}
else throw IllegalStateException("Cannot set the proxy host and port for an already connected session");
}
void HTTPClientSession::setProxyHost(const std::string& host)
{
if (!connected())
_proxyConfig.host = host;
else
throw IllegalStateException("Cannot set the proxy host for an already connected session");
}
void HTTPClientSession::setProxyPort(Poco::UInt16 port)
{
if (!connected())
_proxyConfig.port = port;
else
throw IllegalStateException("Cannot set the proxy port number for an already connected session");
}
void HTTPClientSession::setProxyCredentials(const std::string& username, const std::string& password)
{
_proxyConfig.username = username;
_proxyConfig.password = password;
}
void HTTPClientSession::setProxyUsername(const std::string& username)
{
_proxyConfig.username = username;
}
void HTTPClientSession::setProxyPassword(const std::string& password)
{
_proxyConfig.password = password;
}
void HTTPClientSession::setProxyConfig(const ProxyConfig& config)
{
_proxyConfig = config;
}
void HTTPClientSession::setGlobalProxyConfig(const ProxyConfig& config)
{
_globalProxyConfig = config;
}
void HTTPClientSession::setKeepAliveTimeout(const Poco::Timespan& timeout)
{
_keepAliveTimeout = timeout;
}
std::ostream& HTTPClientSession::sendRequest(HTTPRequest& request)
{
_pRequestStream = 0;
_pResponseStream = 0;
bool keepAlive = getKeepAlive();
if (((connected() && !keepAlive) || mustReconnect()) && !_host.empty())
{
close();
_mustReconnect = false;
}
try
{
if (!connected())
{
_ntlmProxyAuthenticated = false;
reconnect();
}
if (!keepAlive)
{
request.setKeepAlive(false);
}
if (!request.has(HTTPRequest::HOST) && !_host.empty())
{
request.setHost(_host, _port);
}
if (!_proxyConfig.host.empty() && !bypassProxy())
{
std::string prefix = proxyRequestPrefix();
if (!prefix.empty() && request.getURI().compare(0, 7, "http://") != 0 && request.getURI().compare(0, 8, "https://") != 0)
request.setURI(prefix + request.getURI());
if (keepAlive) request.set(HTTPMessage::PROXY_CONNECTION, HTTPMessage::CONNECTION_KEEP_ALIVE);
proxyAuthenticate(request);
}
_reconnect = keepAlive;
return sendRequestImpl(request);
}
catch (Exception&)
{
close();
throw;
}
}
std::ostream& HTTPClientSession::sendRequestImpl(const HTTPRequest& request)
{
_pRequestStream = 0;
_pResponseStream = 0;
clearException();
_responseReceived = false;
_expectResponseBody = request.getMethod() != HTTPRequest::HTTP_HEAD;
const std::string& method = request.getMethod();
if (request.getChunkedTransferEncoding())
{
HTTPHeaderOutputStream hos(*this);
request.write(hos);
_pRequestStream = new HTTPChunkedOutputStream(*this);
}
else if (request.hasContentLength())
{
Poco::CountingOutputStream cs;
request.write(cs);
#if POCO_HAVE_INT64
_pRequestStream = new HTTPFixedLengthOutputStream(*this, request.getContentLength64() + cs.chars());
#else
_pRequestStream = new HTTPFixedLengthOutputStream(*this, request.getContentLength() + cs.chars());
#endif
request.write(*_pRequestStream);
}
else if ((method != HTTPRequest::HTTP_PUT && method != HTTPRequest::HTTP_POST && method != HTTPRequest::HTTP_PATCH) || request.has(HTTPRequest::UPGRADE))
{
Poco::CountingOutputStream cs;
request.write(cs);
_pRequestStream = new HTTPFixedLengthOutputStream(*this, cs.chars());
request.write(*_pRequestStream);
}
else
{
_pRequestStream = new HTTPOutputStream(*this);
request.write(*_pRequestStream);
}
_lastRequest.update();
return *_pRequestStream;
}
void HTTPClientSession::flushRequest()
{
_pRequestStream = 0;
if (networkException()) networkException()->rethrow();
}
std::istream& HTTPClientSession::receiveResponse(HTTPResponse& response)
{
flushRequest();
if (!_responseReceived)
{
do
{
response.clear();
HTTPHeaderInputStream his(*this);
try
{
response.read(his);
}
catch (Exception&)
{
close();
if (networkException())
networkException()->rethrow();
else
throw;
}
}
while (response.getStatus() == HTTPResponse::HTTP_CONTINUE);
}
_mustReconnect = getKeepAlive() && !response.getKeepAlive();
if (!_expectResponseBody || response.getStatus() < 200 || response.getStatus() == HTTPResponse::HTTP_NO_CONTENT || response.getStatus() == HTTPResponse::HTTP_NOT_MODIFIED)
_pResponseStream = new HTTPFixedLengthInputStream(*this, 0);
else if (response.getChunkedTransferEncoding())
_pResponseStream = new HTTPChunkedInputStream(*this);
else if (response.hasContentLength())
#if defined(POCO_HAVE_INT64)
_pResponseStream = new HTTPFixedLengthInputStream(*this, response.getContentLength64());
#else
_pResponseStream = new HTTPFixedLengthInputStream(*this, response.getContentLength());
#endif
else
_pResponseStream = new HTTPInputStream(*this);
return *_pResponseStream;
}
bool HTTPClientSession::peekResponse(HTTPResponse& response)
{
poco_assert (!_responseReceived);
_pRequestStream->flush();
if (networkException()) networkException()->rethrow();
response.clear();
HTTPHeaderInputStream his(*this);
try
{
response.read(his);
}
catch (Exception&)
{
close();
if (networkException())
networkException()->rethrow();
else
throw;
throw;
}
_responseReceived = response.getStatus() != HTTPResponse::HTTP_CONTINUE;
return !_responseReceived;
}
void HTTPClientSession::reset()
{
close();
}
bool HTTPClientSession::secure() const
{
return false;
}
int HTTPClientSession::write(const char* buffer, std::streamsize length)
{
try
{
int rc = HTTPSession::write(buffer, length);
_reconnect = false;
return rc;
}
catch (IOException&)
{
if (_reconnect)
{
close();
reconnect();
int rc = HTTPSession::write(buffer, length);
clearException();
_reconnect = false;
return rc;
}
else throw;
}
}
void HTTPClientSession::reconnect()
{
if (_proxyConfig.host.empty() || bypassProxy())
{
SocketAddress addr(_host, _port);
connect(addr);
}
else
{
SocketAddress addr(_proxyConfig.host, _proxyConfig.port);
connect(addr);
}
}
std::string HTTPClientSession::proxyRequestPrefix() const
{
std::string result("http://");
result.append(_host);
result.append(":");
NumberFormatter::append(result, _port);
return result;
}
bool HTTPClientSession::mustReconnect() const
{
if (!_mustReconnect)
{
Poco::Timestamp now;
return _keepAliveTimeout <= now - _lastRequest;
}
else return true;
}
void HTTPClientSession::proxyAuthenticate(HTTPRequest& request)
{
proxyAuthenticateImpl(request, _proxyConfig);
}
void HTTPClientSession::proxyAuthenticateImpl(HTTPRequest& request, const ProxyConfig& proxyConfig)
{
switch (proxyConfig.authMethod)
{
case PROXY_AUTH_NONE:
break;
case PROXY_AUTH_HTTP_BASIC:
_proxyBasicCreds.setUsername(proxyConfig.username);
_proxyBasicCreds.setPassword(proxyConfig.password);
_proxyBasicCreds.proxyAuthenticate(request);
break;
case PROXY_AUTH_HTTP_DIGEST:
if (HTTPCredentials::hasDigestCredentials(request))
{
_proxyDigestCreds.updateProxyAuthInfo(request);
}
else
{
_proxyDigestCreds.setUsername(proxyConfig.username);
_proxyDigestCreds.setPassword(proxyConfig.password);
proxyAuthenticateDigest(request);
}
case PROXY_AUTH_NTLM:
if (_ntlmProxyAuthenticated)
{
_proxyNTLMCreds.updateProxyAuthInfo(request);
}
else
{
_proxyNTLMCreds.setUsername(proxyConfig.username);
_proxyNTLMCreds.setPassword(proxyConfig.password);
_proxyNTLMCreds.setHost(proxyConfig.host);
proxyAuthenticateNTLM(request);
_ntlmProxyAuthenticated = true;
}
}
}
void HTTPClientSession::proxyAuthenticateDigest(HTTPRequest& request)
{
HTTPResponse response;
request.set(HTTPMessage::PROXY_CONNECTION, HTTPMessage::CONNECTION_KEEP_ALIVE);
sendChallengeRequest(request, response);
_proxyDigestCreds.proxyAuthenticate(request, response);
}
void HTTPClientSession::proxyAuthenticateNTLM(HTTPRequest& request)
{
HTTPResponse response;
request.set(HTTPMessage::PROXY_CONNECTION, HTTPMessage::CONNECTION_KEEP_ALIVE);
_proxyNTLMCreds.proxyAuthenticate(request, std::string());
sendChallengeRequest(request, response);
_proxyNTLMCreds.proxyAuthenticate(request, response);
}
void HTTPClientSession::sendChallengeRequest(const HTTPRequest& request, HTTPResponse& response)
{
if (!connected())
{
reconnect();
}
HTTPRequest challengeRequest(request);
if (challengeRequest.hasContentLength())
{
challengeRequest.setContentLength(0);
}
sendRequestImpl(challengeRequest);
std::istream& istr = receiveResponse(response);
while (istr.good()) istr.get();
}
StreamSocket HTTPClientSession::proxyConnect()
{
ProxyConfig emptyProxyConfig;
HTTPClientSession proxySession(getProxyHost(), getProxyPort(), emptyProxyConfig);
proxySession.setTimeout(getTimeout());
std::string targetAddress(_host);
targetAddress.append(":");
NumberFormatter::append(targetAddress, _port);
HTTPRequest proxyRequest(HTTPRequest::HTTP_CONNECT, targetAddress, HTTPMessage::HTTP_1_1);
HTTPResponse proxyResponse;
proxyRequest.set(HTTPMessage::PROXY_CONNECTION, HTTPMessage::CONNECTION_KEEP_ALIVE);
proxyRequest.set(HTTPRequest::HOST, getHost());
proxySession.proxyAuthenticateImpl(proxyRequest, _proxyConfig);
proxySession.setKeepAlive(true);
proxySession.sendRequest(proxyRequest);
proxySession.receiveResponse(proxyResponse);
if (proxyResponse.getStatus() != HTTPResponse::HTTP_OK)
throw HTTPException("Cannot establish proxy connection", proxyResponse.getReason());
return proxySession.detachSocket();
}
void HTTPClientSession::proxyTunnel()
{
StreamSocket ss = proxyConnect();
attachSocket(ss);
}
bool HTTPClientSession::bypassProxy() const
{
if (!_proxyConfig.nonProxyHosts.empty())
{
return RegularExpression::match(_host, _proxyConfig.nonProxyHosts, RegularExpression::RE_CASELESS | RegularExpression::RE_ANCHORED);
}
else return false;
}
} } // namespace Poco::Net
+392
View File
@@ -0,0 +1,392 @@
//
// HTTPCookie.cpp
//
// Library: Net
// Package: HTTP
// Module: HTTPCookie
//
// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/HTTPCookie.h"
#include "Poco/Net/NameValueCollection.h"
#include "Poco/Timestamp.h"
#include "Poco/DateTime.h"
#include "Poco/DateTimeFormatter.h"
#include "Poco/DateTimeFormat.h"
#include "Poco/DateTimeParser.h"
#include "Poco/NumberFormatter.h"
#include "Poco/NumberParser.h"
#include "Poco/String.h"
#include "Poco/URI.h"
using Poco::Timestamp;
using Poco::DateTime;
using Poco::DateTimeFormatter;
using Poco::DateTimeFormat;
using Poco::DateTimeParser;
using Poco::NumberFormatter;
using Poco::NumberParser;
using Poco::icompare;
namespace Poco {
namespace Net {
HTTPCookie::HTTPCookie():
_version(0),
_secure(false),
_maxAge(-1),
_httpOnly(false),
_sameSite(SAME_SITE_NOT_SPECIFIED)
{
}
HTTPCookie::HTTPCookie(const std::string& name):
_version(0),
_name(name),
_secure(false),
_maxAge(-1),
_httpOnly(false),
_sameSite(SAME_SITE_NOT_SPECIFIED)
{
}
HTTPCookie::HTTPCookie(const NameValueCollection& nvc):
_version(0),
_secure(false),
_maxAge(-1),
_httpOnly(false),
_sameSite(SAME_SITE_NOT_SPECIFIED)
{
for (const auto& p: nvc)
{
const std::string& name = p.first;
const std::string& value = p.second;
if (icompare(name, "comment") == 0)
{
setComment(value);
}
else if (icompare(name, "domain") == 0)
{
setDomain(value);
}
else if (icompare(name, "path") == 0)
{
setPath(value);
}
else if (icompare(name, "priority") == 0)
{
setPriority(value);
}
else if (icompare(name, "max-age") == 0)
{
setMaxAge(NumberParser::parse(value));
}
else if (icompare(name, "secure") == 0)
{
setSecure(true);
}
else if (icompare(name, "expires") == 0)
{
int tzd;
DateTime exp = DateTimeParser::parse(value, tzd);
Timestamp now;
setMaxAge((int) ((exp.timestamp() - now) / Timestamp::resolution()));
}
else if (icompare(name, "SameSite") == 0)
{
if (icompare(value, "None") == 0)
_sameSite = SAME_SITE_NONE;
else if (icompare(value, "Lax") == 0)
_sameSite = SAME_SITE_LAX;
else if (icompare(value, "Strict") == 0)
_sameSite = SAME_SITE_STRICT;
}
else if (icompare(name, "version") == 0)
{
setVersion(NumberParser::parse(value));
}
else if (icompare(name, "HttpOnly") == 0)
{
setHttpOnly(true);
}
else
{
setName(name);
setValue(value);
}
}
}
HTTPCookie::HTTPCookie(const std::string& name, const std::string& value):
_version(0),
_name(name),
_value(value),
_secure(false),
_maxAge(-1),
_httpOnly(false),
_sameSite(SAME_SITE_NOT_SPECIFIED)
{
}
HTTPCookie::HTTPCookie(const HTTPCookie& cookie):
_version(cookie._version),
_name(cookie._name),
_value(cookie._value),
_comment(cookie._comment),
_domain(cookie._domain),
_path(cookie._path),
_priority(cookie._priority),
_secure(cookie._secure),
_maxAge(cookie._maxAge),
_httpOnly(cookie._httpOnly),
_sameSite(cookie._sameSite)
{
}
HTTPCookie::~HTTPCookie()
{
}
HTTPCookie& HTTPCookie::operator = (const HTTPCookie& cookie)
{
if (&cookie != this)
{
_version = cookie._version;
_name = cookie._name;
_value = cookie._value;
_comment = cookie._comment;
_domain = cookie._domain;
_path = cookie._path;
_priority = cookie._priority;
_secure = cookie._secure;
_maxAge = cookie._maxAge;
_httpOnly = cookie._httpOnly;
_sameSite = cookie._sameSite;
}
return *this;
}
void HTTPCookie::setVersion(int version)
{
_version = version;
}
void HTTPCookie::setName(const std::string& name)
{
_name = name;
}
void HTTPCookie::setValue(const std::string& value)
{
_value = value;
}
void HTTPCookie::setComment(const std::string& comment)
{
_comment = comment;
}
void HTTPCookie::setDomain(const std::string& domain)
{
_domain = domain;
}
void HTTPCookie::setPath(const std::string& path)
{
_path = path;
}
void HTTPCookie::setPriority(const std::string& priority)
{
_priority = priority;
}
void HTTPCookie::setSecure(bool secure)
{
_secure = secure;
}
void HTTPCookie::setMaxAge(int maxAge)
{
_maxAge = maxAge;
}
void HTTPCookie::setHttpOnly(bool flag)
{
_httpOnly = flag;
}
void HTTPCookie::setSameSite(SameSite value)
{
_sameSite = value;
}
std::string HTTPCookie::toString() const
{
std::string result;
result.reserve(256);
result.append(_name);
result.append("=");
if (_version == 0)
{
// Netscape cookie
result.append(_value);
if (!_domain.empty())
{
result.append("; domain=");
result.append(_domain);
}
if (!_path.empty())
{
result.append("; path=");
result.append(_path);
}
if (!_priority.empty())
{
result.append("; Priority=");
result.append(_priority);
}
if (_maxAge != -1)
{
Timestamp ts;
ts += _maxAge * Timestamp::resolution();
result.append("; expires=");
DateTimeFormatter::append(result, ts, DateTimeFormat::HTTP_FORMAT);
}
switch (_sameSite)
{
case SAME_SITE_NONE:
result.append("; SameSite=None");
break;
case SAME_SITE_LAX:
result.append("; SameSite=Lax");
break;
case SAME_SITE_STRICT:
result.append("; SameSite=Strict");
break;
case SAME_SITE_NOT_SPECIFIED:
break;
}
if (_secure)
{
result.append("; secure");
}
if (_httpOnly)
{
result.append("; HttpOnly");
}
}
else
{
// RFC 2109 cookie
result.append("\"");
result.append(_value);
result.append("\"");
if (!_comment.empty())
{
result.append("; Comment=\"");
result.append(_comment);
result.append("\"");
}
if (!_domain.empty())
{
result.append("; Domain=\"");
result.append(_domain);
result.append("\"");
}
if (!_path.empty())
{
result.append("; Path=\"");
result.append(_path);
result.append("\"");
}
if (!_priority.empty())
{
result.append("; Priority=\"");
result.append(_priority);
result.append("\"");
}
if (_maxAge != -1)
{
result.append("; Max-Age=\"");
NumberFormatter::append(result, _maxAge);
result.append("\"");
}
switch (_sameSite)
{
case SAME_SITE_NONE:
result.append("; SameSite=None");
break;
case SAME_SITE_LAX:
result.append("; SameSite=Lax");
break;
case SAME_SITE_STRICT:
result.append("; SameSite=Strict");
break;
case SAME_SITE_NOT_SPECIFIED:
break;
}
if (_secure)
{
result.append("; secure");
}
if (_httpOnly)
{
result.append("; HttpOnly");
}
result.append("; Version=\"1\"");
}
return result;
}
namespace
{
static const std::string ILLEGAL_CHARS("()[]/|\\',;");
}
std::string HTTPCookie::escape(const std::string& str)
{
std::string result;
Poco::URI::encode(str, ILLEGAL_CHARS, result);
return result;
}
std::string HTTPCookie::unescape(const std::string& str)
{
std::string result;
Poco::URI::decode(str, result);
return result;
}
} } // namespace Poco::Net
+260
View File
@@ -0,0 +1,260 @@
//
// HTTPCredentials.cpp
//
// Library: Net
// Package: HTTP
// Module: HTTPCredentials
//
// Copyright (c) 2011, Anton V. Yabchinskiy (arn at bestmx dot ru).
// Copyright (c) 2012, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/HTTPAuthenticationParams.h"
#include "Poco/Net/HTTPBasicCredentials.h"
#include "Poco/Net/HTTPCredentials.h"
#include "Poco/Net/HTTPRequest.h"
#include "Poco/Net/HTTPResponse.h"
#include "Poco/Net/NetException.h"
#include "Poco/String.h"
#include "Poco/Ascii.h"
#include "Poco/URI.h"
using Poco::icompare;
namespace Poco {
namespace Net {
HTTPCredentials::HTTPCredentials()
{
}
HTTPCredentials::HTTPCredentials(const std::string& username, const std::string& password):
_digest(username, password)
{
}
HTTPCredentials::~HTTPCredentials()
{
}
void HTTPCredentials::clear()
{
_digest.clear();
_ntlm.clear();
}
void HTTPCredentials::fromUserInfo(const std::string& userInfo)
{
std::string username;
std::string password;
extractCredentials(userInfo, username, password);
setUsername(username);
setPassword(password);
_digest.reset();
}
void HTTPCredentials::fromURI(const URI& uri)
{
std::string username;
std::string password;
extractCredentials(uri, username, password);
setUsername(username);
setPassword(password);
setHost(uri.getHost());
_digest.reset();
}
void HTTPCredentials::authenticate(HTTPRequest& request, const HTTPResponse& response)
{
for (HTTPResponse::ConstIterator iter = response.find(HTTPAuthenticationParams::WWW_AUTHENTICATE); iter != response.end(); ++iter)
{
if (isBasicCredentials(iter->second))
{
HTTPBasicCredentials(_digest.getUsername(), _digest.getPassword()).authenticate(request);
return;
}
else if (isDigestCredentials(iter->second))
{
_digest.authenticate(request, HTTPAuthenticationParams(iter->second.substr(7)));
return;
}
else if (isNTLMCredentials(iter->second))
{
_ntlm.setUsername(_digest.getUsername());
_ntlm.setPassword(_digest.getPassword());
if (_ntlm.getHost().empty())
{
_ntlm.setHost(request.getHost());
}
_ntlm.authenticate(request, iter->second.substr(5));
return;
}
}
}
void HTTPCredentials::updateAuthInfo(HTTPRequest& request)
{
if (request.has(HTTPRequest::AUTHORIZATION))
{
const std::string& authorization = request.get(HTTPRequest::AUTHORIZATION);
if (isBasicCredentials(authorization))
{
HTTPBasicCredentials(_digest.getUsername(), _digest.getPassword()).authenticate(request);
}
else if (isDigestCredentials(authorization))
{
_digest.updateAuthInfo(request);
}
else if (isNTLMCredentials(authorization))
{
_ntlm.updateAuthInfo(request);
}
}
}
void HTTPCredentials::proxyAuthenticate(HTTPRequest& request, const HTTPResponse& response)
{
for (HTTPResponse::ConstIterator iter = response.find(HTTPAuthenticationParams::PROXY_AUTHENTICATE); iter != response.end(); ++iter)
{
if (isBasicCredentials(iter->second))
{
HTTPBasicCredentials(_digest.getUsername(), _digest.getPassword()).proxyAuthenticate(request);
return;
}
else if (isDigestCredentials(iter->second))
{
_digest.proxyAuthenticate(request, HTTPAuthenticationParams(iter->second.substr(7)));
return;
}
else if (isNTLMCredentials(iter->second))
{
_ntlm.setUsername(_digest.getUsername());
_ntlm.setPassword(_digest.getPassword());
_ntlm.proxyAuthenticate(request, iter->second.substr(5));
return;
}
}
}
void HTTPCredentials::updateProxyAuthInfo(HTTPRequest& request)
{
if (request.has(HTTPRequest::PROXY_AUTHORIZATION))
{
const std::string& authorization = request.get(HTTPRequest::PROXY_AUTHORIZATION);
if (isBasicCredentials(authorization))
{
HTTPBasicCredentials(_digest.getUsername(), _digest.getPassword()).proxyAuthenticate(request);
}
else if (isDigestCredentials(authorization))
{
_digest.updateProxyAuthInfo(request);
}
else if (isNTLMCredentials(authorization))
{
_ntlm.updateProxyAuthInfo(request);
}
}
}
bool HTTPCredentials::isBasicCredentials(const std::string& header)
{
return icompare(header, 0, 5, "Basic") == 0 && (header.size() > 5 ? Poco::Ascii::isSpace(header[5]) : true);
}
bool HTTPCredentials::isDigestCredentials(const std::string& header)
{
return icompare(header, 0, 6, "Digest") == 0 && (header.size() > 6 ? Poco::Ascii::isSpace(header[6]) : true);
}
bool HTTPCredentials::isNTLMCredentials(const std::string& header)
{
return icompare(header, 0, 4, "NTLM") == 0 && (header.size() > 5 ? Poco::Ascii::isSpace(header[5]) : true);
}
bool HTTPCredentials::hasBasicCredentials(const HTTPRequest& request)
{
return request.has(HTTPRequest::AUTHORIZATION) && isBasicCredentials(request.get(HTTPRequest::AUTHORIZATION));
}
bool HTTPCredentials::hasDigestCredentials(const HTTPRequest& request)
{
return request.has(HTTPRequest::AUTHORIZATION) && isDigestCredentials(request.get(HTTPRequest::AUTHORIZATION));
}
bool HTTPCredentials::hasNTLMCredentials(const HTTPRequest& request)
{
return request.has(HTTPRequest::AUTHORIZATION) && isNTLMCredentials(request.get(HTTPRequest::AUTHORIZATION));
}
bool HTTPCredentials::hasProxyBasicCredentials(const HTTPRequest& request)
{
return request.has(HTTPRequest::PROXY_AUTHORIZATION) && isBasicCredentials(request.get(HTTPRequest::PROXY_AUTHORIZATION));
}
bool HTTPCredentials::hasProxyDigestCredentials(const HTTPRequest& request)
{
return request.has(HTTPRequest::PROXY_AUTHORIZATION) && isDigestCredentials(request.get(HTTPRequest::PROXY_AUTHORIZATION));
}
bool HTTPCredentials::hasProxyNTLMCredentials(const HTTPRequest& request)
{
return request.has(HTTPRequest::PROXY_AUTHORIZATION) && isNTLMCredentials(request.get(HTTPRequest::PROXY_AUTHORIZATION));
}
void HTTPCredentials::extractCredentials(const std::string& userInfo, std::string& username, std::string& password)
{
const std::string::size_type p = userInfo.find(':');
if (p != std::string::npos)
{
username.assign(userInfo, 0, p);
password.assign(userInfo, p + 1, std::string::npos);
}
else
{
username.assign(userInfo);
password.clear();
}
}
void HTTPCredentials::extractCredentials(const Poco::URI& uri, std::string& username, std::string& password)
{
if (!uri.getUserInfo().empty())
{
extractCredentials(uri.getUserInfo(), username, password);
}
}
} } // namespace Poco::Net
+313
View File
@@ -0,0 +1,313 @@
//
// HTTPDigestCredentials.cpp
//
// Library: Net
// Package: HTTP
// Module: HTTPDigestCredentials
//
// Copyright (c) 2011, Anton V. Yabchinskiy (arn at bestmx dot ru).
// Copyright (c) 2012, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/DateTime.h"
#include "Poco/DateTimeFormat.h"
#include "Poco/DateTimeFormatter.h"
#include "Poco/Exception.h"
#include "Poco/MD5Engine.h"
#include "Poco/Net/HTTPDigestCredentials.h"
#include "Poco/Net/HTTPRequest.h"
#include "Poco/Net/HTTPResponse.h"
#include "Poco/NumberFormatter.h"
#include "Poco/StringTokenizer.h"
namespace
{
std::string digest(Poco::DigestEngine& engine,
const std::string& a,
const std::string& b,
const std::string& c = std::string(),
const std::string& d = std::string(),
const std::string& e = std::string(),
const std::string& f = std::string())
{
engine.reset();
engine.update(a);
engine.update(':');
engine.update(b);
if (!c.empty())
{
engine.update(':');
engine.update(c);
if (!d.empty())
{
engine.update(':');
engine.update(d);
engine.update(':');
engine.update(e);
engine.update(':');
engine.update(f);
}
}
return Poco::DigestEngine::digestToHex(engine.digest());
}
std::string formatNonceCounter(int counter)
{
return Poco::NumberFormatter::formatHex(counter, 8);
}
}
namespace Poco {
namespace Net {
const std::string HTTPDigestCredentials::SCHEME = "Digest";
const std::string HTTPDigestCredentials::DEFAULT_ALGORITHM("MD5");
const std::string HTTPDigestCredentials::DEFAULT_QOP("");
const std::string HTTPDigestCredentials::NONCE_PARAM("nonce");
const std::string HTTPDigestCredentials::REALM_PARAM("realm");
const std::string HTTPDigestCredentials::QOP_PARAM("qop");
const std::string HTTPDigestCredentials::ALGORITHM_PARAM("algorithm");
const std::string HTTPDigestCredentials::USERNAME_PARAM("username");
const std::string HTTPDigestCredentials::OPAQUE_PARAM("opaque");
const std::string HTTPDigestCredentials::URI_PARAM("uri");
const std::string HTTPDigestCredentials::RESPONSE_PARAM("response");
const std::string HTTPDigestCredentials::AUTH_PARAM("auth");
const std::string HTTPDigestCredentials::CNONCE_PARAM("cnonce");
const std::string HTTPDigestCredentials::NC_PARAM("nc");
int HTTPDigestCredentials::_nonceCounter(0);
Poco::FastMutex HTTPDigestCredentials::_nonceMutex;
HTTPDigestCredentials::HTTPDigestCredentials()
{
}
HTTPDigestCredentials::HTTPDigestCredentials(const std::string& username, const std::string& password):
_username(username),
_password(password)
{
}
HTTPDigestCredentials::~HTTPDigestCredentials()
{
}
void HTTPDigestCredentials::reset()
{
_requestAuthParams.clear();
_nc.clear();
}
void HTTPDigestCredentials::setUsername(const std::string& username)
{
_username = username;
}
void HTTPDigestCredentials::setPassword(const std::string& password)
{
_password = password;
}
void HTTPDigestCredentials::clear()
{
_username.clear();
_password.clear();
}
void HTTPDigestCredentials::authenticate(HTTPRequest& request, const HTTPResponse& response)
{
authenticate(request, HTTPAuthenticationParams(response));
}
void HTTPDigestCredentials::authenticate(HTTPRequest& request, const HTTPAuthenticationParams& responseAuthParams)
{
createAuthParams(request, responseAuthParams);
request.setCredentials(SCHEME, _requestAuthParams.toString());
}
void HTTPDigestCredentials::updateAuthInfo(HTTPRequest& request)
{
updateAuthParams(request);
request.setCredentials(SCHEME, _requestAuthParams.toString());
}
void HTTPDigestCredentials::proxyAuthenticate(HTTPRequest& request, const HTTPResponse& response)
{
proxyAuthenticate(request, HTTPAuthenticationParams(response, HTTPAuthenticationParams::PROXY_AUTHENTICATE));
}
void HTTPDigestCredentials::proxyAuthenticate(HTTPRequest& request, const HTTPAuthenticationParams& responseAuthParams)
{
createAuthParams(request, responseAuthParams);
request.setProxyCredentials(SCHEME, _requestAuthParams.toString());
}
void HTTPDigestCredentials::updateProxyAuthInfo(HTTPRequest& request)
{
updateAuthParams(request);
request.setProxyCredentials(SCHEME, _requestAuthParams.toString());
}
std::string HTTPDigestCredentials::createNonce()
{
Poco::FastMutex::ScopedLock lock(_nonceMutex);
MD5Engine md5;
Timestamp::TimeVal now = Timestamp().epochMicroseconds();
md5.update(&_nonceCounter, sizeof(_nonceCounter));
md5.update(&now, sizeof(now));
++_nonceCounter;
return DigestEngine::digestToHex(md5.digest());
}
void HTTPDigestCredentials::createAuthParams(const HTTPRequest& request, const HTTPAuthenticationParams& responseAuthParams)
{
// Not implemented: "domain" auth parameter and integrity protection.
if (!responseAuthParams.has(NONCE_PARAM) || !responseAuthParams.has(REALM_PARAM))
throw InvalidArgumentException("Invalid HTTP authentication parameters");
const std::string& algorithm = responseAuthParams.get(ALGORITHM_PARAM, DEFAULT_ALGORITHM);
if (icompare(algorithm, DEFAULT_ALGORITHM) != 0)
throw NotImplementedException("Unsupported digest algorithm", algorithm);
const std::string& nonce = responseAuthParams.get(NONCE_PARAM);
const std::string& qop = responseAuthParams.get(QOP_PARAM, DEFAULT_QOP);
const std::string& realm = responseAuthParams.getRealm();
_requestAuthParams.clear();
_requestAuthParams.set(USERNAME_PARAM, _username);
_requestAuthParams.set(NONCE_PARAM, nonce);
_requestAuthParams.setRealm(realm);
if (responseAuthParams.has(OPAQUE_PARAM))
{
_requestAuthParams.set(OPAQUE_PARAM, responseAuthParams.get(OPAQUE_PARAM));
}
if (qop.empty())
{
updateAuthParams(request);
}
else
{
Poco::StringTokenizer tok(qop, ",", Poco::StringTokenizer::TOK_TRIM);
bool qopSupported = false;
for (Poco::StringTokenizer::Iterator it = tok.begin(); it != tok.end(); ++it)
{
if (icompare(*it, AUTH_PARAM) == 0)
{
qopSupported = true;
_requestAuthParams.set(CNONCE_PARAM, createNonce());
_requestAuthParams.set(QOP_PARAM, *it);
updateAuthParams(request);
break;
}
}
if (!qopSupported)
throw NotImplementedException("Unsupported QoP requested", qop);
}
}
void HTTPDigestCredentials::updateAuthParams(const HTTPRequest& request)
{
MD5Engine engine;
const std::string qop = _requestAuthParams.get(QOP_PARAM, DEFAULT_QOP);
const std::string realm = _requestAuthParams.getRealm();
const std::string nonce = _requestAuthParams.get(NONCE_PARAM);
_requestAuthParams.set(URI_PARAM, request.getURI());
if (qop.empty())
{
const std::string ha1 = digest(engine, _username, realm, _password);
const std::string ha2 = digest(engine, request.getMethod(), request.getURI());
_requestAuthParams.set(RESPONSE_PARAM, digest(engine, ha1, nonce, ha2));
}
else if (icompare(qop, AUTH_PARAM) == 0)
{
const std::string cnonce = _requestAuthParams.get(CNONCE_PARAM);
const std::string ha1 = digest(engine, _username, realm, _password);
const std::string ha2 = digest(engine, request.getMethod(), request.getURI());
const std::string nc = formatNonceCounter(updateNonceCounter(nonce));
_requestAuthParams.set(NC_PARAM, nc);
_requestAuthParams.set(RESPONSE_PARAM, digest(engine, ha1, nonce, nc, cnonce, qop, ha2));
}
}
bool HTTPDigestCredentials::verifyAuthInfo(const HTTPRequest& request) const
{
HTTPAuthenticationParams params(request);
return verifyAuthParams(request, params);
}
bool HTTPDigestCredentials::verifyAuthParams(const HTTPRequest& request, const HTTPAuthenticationParams& params) const
{
const std::string& nonce = params.get(NONCE_PARAM);
const std::string& realm = params.getRealm();
const std::string& qop = params.get(QOP_PARAM, DEFAULT_QOP);
std::string response;
MD5Engine engine;
if (qop.empty())
{
const std::string ha1 = digest(engine, _username, realm, _password);
const std::string ha2 = digest(engine, request.getMethod(), request.getURI());
response = digest(engine, ha1, nonce, ha2);
}
else if (icompare(qop, AUTH_PARAM) == 0)
{
const std::string& cnonce = params.get(CNONCE_PARAM);
const std::string& nc = params.get(NC_PARAM);
const std::string ha1 = digest(engine, _username, realm, _password);
const std::string ha2 = digest(engine, request.getMethod(), request.getURI());
response = digest(engine, ha1, nonce, nc, cnonce, qop, ha2);
}
return response == params.get(RESPONSE_PARAM);
}
int HTTPDigestCredentials::updateNonceCounter(const std::string& nonce)
{
NonceCounterMap::iterator iter = _nc.find(nonce);
if (iter == _nc.end())
{
iter = _nc.insert(NonceCounterMap::value_type(nonce, 0)).first;
}
iter->second++;
return iter->second;
}
} } // namespace Poco::Net
+181
View File
@@ -0,0 +1,181 @@
//
// HTTPFixedLengthStream.cpp
//
// Library: Net
// Package: HTTP
// Module: HTTPFixedLengthStream
//
// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/HTTPFixedLengthStream.h"
#include "Poco/Net/HTTPSession.h"
using Poco::BufferedStreamBuf;
namespace Poco {
namespace Net {
//
// HTTPFixedLengthStreamBuf
//
HTTPFixedLengthStreamBuf::HTTPFixedLengthStreamBuf(HTTPSession& session, ContentLength length, openmode mode):
HTTPBasicStreamBuf(HTTPBufferAllocator::BUFFER_SIZE, mode),
_session(session),
_length(length),
_count(0)
{
}
HTTPFixedLengthStreamBuf::~HTTPFixedLengthStreamBuf()
{
}
int HTTPFixedLengthStreamBuf::readFromDevice(char* buffer, std::streamsize length)
{
int n = 0;
if (_count < _length)
{
if (_count + length > _length)
length = static_cast<std::streamsize>(_length - _count);
n = _session.read(buffer, length);
if (n > 0) _count += n;
}
return n;
}
int HTTPFixedLengthStreamBuf::writeToDevice(const char* buffer, std::streamsize length)
{
int n = 0;
if (_count < _length)
{
if (_count + length > _length)
length = static_cast<std::streamsize>(_length - _count);
n = _session.write(buffer, length);
if (n > 0) _count += n;
}
return n;
}
//
// HTTPFixedLengthIOS
//
HTTPFixedLengthIOS::HTTPFixedLengthIOS(HTTPSession& session, HTTPFixedLengthStreamBuf::ContentLength length, HTTPFixedLengthStreamBuf::openmode mode):
_buf(session, length, mode)
{
poco_ios_init(&_buf);
}
HTTPFixedLengthIOS::~HTTPFixedLengthIOS()
{
try
{
_buf.sync();
}
catch (...)
{
}
}
HTTPFixedLengthStreamBuf* HTTPFixedLengthIOS::rdbuf()
{
return &_buf;
}
//
// HTTPFixedLengthInputStream
//
Poco::MemoryPool HTTPFixedLengthInputStream::_pool(sizeof(HTTPFixedLengthInputStream));
HTTPFixedLengthInputStream::HTTPFixedLengthInputStream(HTTPSession& session, HTTPFixedLengthStreamBuf::ContentLength length):
HTTPFixedLengthIOS(session, length, std::ios::in),
std::istream(&_buf)
{
}
HTTPFixedLengthInputStream::~HTTPFixedLengthInputStream()
{
}
void* HTTPFixedLengthInputStream::operator new(std::size_t size)
{
return _pool.get();
}
void HTTPFixedLengthInputStream::operator delete(void* ptr)
{
try
{
_pool.release(ptr);
}
catch (...)
{
poco_unexpected();
}
}
//
// HTTPFixedLengthOutputStream
//
Poco::MemoryPool HTTPFixedLengthOutputStream::_pool(sizeof(HTTPFixedLengthOutputStream));
HTTPFixedLengthOutputStream::HTTPFixedLengthOutputStream(HTTPSession& session, HTTPFixedLengthStreamBuf::ContentLength length):
HTTPFixedLengthIOS(session, length, std::ios::out),
std::ostream(&_buf)
{
}
HTTPFixedLengthOutputStream::~HTTPFixedLengthOutputStream()
{
}
void* HTTPFixedLengthOutputStream::operator new(std::size_t size)
{
return _pool.get();
}
void HTTPFixedLengthOutputStream::operator delete(void* ptr)
{
try
{
_pool.release(ptr);
}
catch (...)
{
poco_unexpected();
}
}
} } // namespace Poco::Net
+178
View File
@@ -0,0 +1,178 @@
//
// HTTPHeaderStream.cpp
//
// Library: Net
// Package: HTTP
// Module: HTTPHeaderStream
//
// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/HTTPHeaderStream.h"
#include "Poco/Net/HTTPSession.h"
namespace Poco {
namespace Net {
//
// HTTPHeaderStreamBuf
//
HTTPHeaderStreamBuf::HTTPHeaderStreamBuf(HTTPSession& session, openmode mode):
HTTPBasicStreamBuf(HTTPBufferAllocator::BUFFER_SIZE, mode),
_session(session),
_end(false)
{
}
HTTPHeaderStreamBuf::~HTTPHeaderStreamBuf()
{
}
int HTTPHeaderStreamBuf::readFromDevice(char* buffer, std::streamsize length)
{
// read line-by-line; an empty line denotes the end of the headers.
static const int eof = std::char_traits<char>::eof();
if (_end) return 0;
int n = 0;
int ch = _session.get();
while (ch != eof && ch != '\n' && n < length - 1)
{
*buffer++ = (char) ch; ++n;
ch = _session.get();
}
if (ch != eof)
{
*buffer++ = (char) ch; ++n;
if (n == 2) _end = true;
}
return n;
}
int HTTPHeaderStreamBuf::writeToDevice(const char* buffer, std::streamsize length)
{
return _session.write(buffer, length);
}
//
// HTTPHeaderIOS
//
HTTPHeaderIOS::HTTPHeaderIOS(HTTPSession& session, HTTPHeaderStreamBuf::openmode mode):
_buf(session, mode)
{
poco_ios_init(&_buf);
}
HTTPHeaderIOS::~HTTPHeaderIOS()
{
try
{
_buf.sync();
}
catch (...)
{
}
}
HTTPHeaderStreamBuf* HTTPHeaderIOS::rdbuf()
{
return &_buf;
}
//
// HTTPHeaderInputStream
//
Poco::MemoryPool HTTPHeaderInputStream::_pool(sizeof(HTTPHeaderInputStream));
HTTPHeaderInputStream::HTTPHeaderInputStream(HTTPSession& session):
HTTPHeaderIOS(session, std::ios::in),
std::istream(&_buf)
{
}
HTTPHeaderInputStream::~HTTPHeaderInputStream()
{
}
void* HTTPHeaderInputStream::operator new(std::size_t size)
{
return _pool.get();
}
void HTTPHeaderInputStream::operator delete(void* ptr)
{
try
{
_pool.release(ptr);
}
catch (...)
{
poco_unexpected();
}
}
//
// HTTPHeaderOutputStream
//
Poco::MemoryPool HTTPHeaderOutputStream::_pool(sizeof(HTTPHeaderOutputStream));
HTTPHeaderOutputStream::HTTPHeaderOutputStream(HTTPSession& session):
HTTPHeaderIOS(session, std::ios::out),
std::ostream(&_buf)
{
}
HTTPHeaderOutputStream::~HTTPHeaderOutputStream()
{
}
void* HTTPHeaderOutputStream::operator new(std::size_t size)
{
return _pool.get();
}
void HTTPHeaderOutputStream::operator delete(void* ptr)
{
try
{
_pool.release(ptr);
}
catch (...)
{
poco_unexpected();
}
}
} } // namespace Poco::Net
+65
View File
@@ -0,0 +1,65 @@
//
// HTTPIOStream.cpp
//
// Library: Net
// Package: HTTP
// Module: HTTPIOStream
//
// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/HTTPIOStream.h"
#include "Poco/Net/HTTPClientSession.h"
using Poco::UnbufferedStreamBuf;
namespace Poco {
namespace Net {
HTTPResponseStreamBuf::HTTPResponseStreamBuf(std::istream& istr):
_istr(istr)
{
// make sure exceptions from underlying string propagate
_istr.exceptions(std::ios::badbit);
}
HTTPResponseStreamBuf::~HTTPResponseStreamBuf()
{
}
HTTPResponseIOS::HTTPResponseIOS(std::istream& istr):
_buf(istr)
{
poco_ios_init(&_buf);
}
HTTPResponseIOS::~HTTPResponseIOS()
{
}
HTTPResponseStream::HTTPResponseStream(std::istream& istr, HTTPClientSession* pSession):
HTTPResponseIOS(istr),
std::istream(&_buf),
_pSession(pSession)
{
}
HTTPResponseStream::~HTTPResponseStream()
{
delete _pSession;
}
} } // namespace Poco::Net
+203
View File
@@ -0,0 +1,203 @@
//
// HTTPMessage.cpp
//
// Library: Net
// Package: HTTP
// Module: HTTPMessage
//
// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/HTTPMessage.h"
#include "Poco/Net/MediaType.h"
#include "Poco/NumberFormatter.h"
#include "Poco/NumberParser.h"
#include "Poco/String.h"
using Poco::NumberFormatter;
using Poco::NumberParser;
using Poco::icompare;
namespace Poco {
namespace Net {
const std::string HTTPMessage::HTTP_1_0 = "HTTP/1.0";
const std::string HTTPMessage::HTTP_1_1 = "HTTP/1.1";
const std::string HTTPMessage::IDENTITY_TRANSFER_ENCODING = "identity";
const std::string HTTPMessage::CHUNKED_TRANSFER_ENCODING = "chunked";
const int HTTPMessage::UNKNOWN_CONTENT_LENGTH = -1;
const std::string HTTPMessage::UNKNOWN_CONTENT_TYPE;
const std::string HTTPMessage::CONTENT_LENGTH = "Content-Length";
const std::string HTTPMessage::CONTENT_TYPE = "Content-Type";
const std::string HTTPMessage::TRANSFER_ENCODING = "Transfer-Encoding";
const std::string HTTPMessage::CONNECTION = "Connection";
const std::string HTTPMessage::PROXY_CONNECTION = "Proxy-Connection";
const std::string HTTPMessage::CONNECTION_KEEP_ALIVE = "Keep-Alive";
const std::string HTTPMessage::CONNECTION_CLOSE = "Close";
const std::string HTTPMessage::EMPTY;
HTTPMessage::HTTPMessage():
_version(HTTP_1_0)
{
}
HTTPMessage::HTTPMessage(const std::string& version):
_version(version)
{
}
HTTPMessage::HTTPMessage(const HTTPMessage& other):
MessageHeader(other),
_version(other._version)
{
}
HTTPMessage::~HTTPMessage()
{
}
HTTPMessage& HTTPMessage::operator = (const HTTPMessage& other)
{
if (this != &other)
{
MessageHeader::operator = (other);
_version = other._version;
}
return *this;
}
void HTTPMessage::setVersion(const std::string& version)
{
_version = version;
}
void HTTPMessage::setContentLength(std::streamsize length)
{
if (length != UNKNOWN_CONTENT_LENGTH)
set(CONTENT_LENGTH, NumberFormatter::format(length));
else
erase(CONTENT_LENGTH);
}
std::streamsize HTTPMessage::getContentLength() const
{
const std::string& contentLength = get(CONTENT_LENGTH, EMPTY);
if (!contentLength.empty())
{
if (sizeof(std::streamsize) == sizeof(Poco::Int64))
return static_cast<std::streamsize>(NumberParser::parse64(contentLength));
else
return static_cast<std::streamsize>(NumberParser::parse(contentLength));
}
else return UNKNOWN_CONTENT_LENGTH;
}
#if defined(POCO_HAVE_INT64)
void HTTPMessage::setContentLength64(Poco::Int64 length)
{
if (length != UNKNOWN_CONTENT_LENGTH)
set(CONTENT_LENGTH, NumberFormatter::format(length));
else
erase(CONTENT_LENGTH);
}
Poco::Int64 HTTPMessage::getContentLength64() const
{
const std::string& contentLength = get(CONTENT_LENGTH, EMPTY);
if (!contentLength.empty())
{
return NumberParser::parse64(contentLength);
}
else return UNKNOWN_CONTENT_LENGTH;
}
#endif // defined(POCO_HAVE_INT64)
void HTTPMessage::setTransferEncoding(const std::string& transferEncoding)
{
if (icompare(transferEncoding, IDENTITY_TRANSFER_ENCODING) == 0)
erase(TRANSFER_ENCODING);
else
set(TRANSFER_ENCODING, transferEncoding);
}
const std::string& HTTPMessage::getTransferEncoding() const
{
return get(TRANSFER_ENCODING, IDENTITY_TRANSFER_ENCODING);
}
void HTTPMessage::setChunkedTransferEncoding(bool flag)
{
if (flag)
setTransferEncoding(CHUNKED_TRANSFER_ENCODING);
else
setTransferEncoding(IDENTITY_TRANSFER_ENCODING);
}
bool HTTPMessage::getChunkedTransferEncoding() const
{
return icompare(getTransferEncoding(), CHUNKED_TRANSFER_ENCODING) == 0;
}
void HTTPMessage::setContentType(const std::string& mediaType)
{
if (mediaType.empty())
erase(CONTENT_TYPE);
else
set(CONTENT_TYPE, mediaType);
}
void HTTPMessage::setContentType(const MediaType& mediaType)
{
setContentType(mediaType.toString());
}
const std::string& HTTPMessage::getContentType() const
{
return get(CONTENT_TYPE, UNKNOWN_CONTENT_TYPE);
}
void HTTPMessage::setKeepAlive(bool keepAlive)
{
if (keepAlive)
set(CONNECTION, CONNECTION_KEEP_ALIVE);
else
set(CONNECTION, CONNECTION_CLOSE);
}
bool HTTPMessage::getKeepAlive() const
{
const std::string& connection = get(CONNECTION, EMPTY);
if (!connection.empty())
return icompare(connection, CONNECTION_CLOSE) != 0;
else
return getVersion() == HTTP_1_1;
}
} } // namespace Poco::Net
+185
View File
@@ -0,0 +1,185 @@
//
// HTTPNTLMCredentials.cpp
//
// Library: Net
// Package: HTTP
// Module: HTTPNTLMCredentials
//
// Copyright (c) 2019, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/HTTPNTLMCredentials.h"
#include "Poco/Net/NTLMCredentials.h"
#include "Poco/Net/HTTPAuthenticationParams.h"
#include "Poco/Net/HTTPRequest.h"
#include "Poco/Net/HTTPResponse.h"
#include "Poco/Net/NetException.h"
#include "Poco/DateTime.h"
#include "Poco/NumberFormatter.h"
#include "Poco/Exception.h"
namespace Poco {
namespace Net {
const std::string HTTPNTLMCredentials::SCHEME = "NTLM";
HTTPNTLMCredentials::HTTPNTLMCredentials()
{
}
HTTPNTLMCredentials::HTTPNTLMCredentials(const std::string& username, const std::string& password):
_username(username),
_password(password)
{
}
HTTPNTLMCredentials::~HTTPNTLMCredentials()
{
}
void HTTPNTLMCredentials::reset()
{
}
void HTTPNTLMCredentials::clear()
{
_username.clear();
_password.clear();
_host.clear();
}
void HTTPNTLMCredentials::setUsername(const std::string& username)
{
_username = username;
}
void HTTPNTLMCredentials::setPassword(const std::string& password)
{
_password = password;
}
void HTTPNTLMCredentials::setHost(const std::string& host)
{
_host = host;
}
void HTTPNTLMCredentials::authenticate(HTTPRequest& request, const HTTPResponse& response)
{
HTTPAuthenticationParams params(response);
authenticate(request, params.get(HTTPAuthenticationParams::NTLM, ""));
}
void HTTPNTLMCredentials::authenticate(HTTPRequest& request, const std::string& ntlmChallengeBase64)
{
std::string ntlmMessage = createNTLMMessage(ntlmChallengeBase64);
request.setCredentials(SCHEME, ntlmMessage);
}
void HTTPNTLMCredentials::updateAuthInfo(HTTPRequest& request)
{
request.removeCredentials();
}
void HTTPNTLMCredentials::proxyAuthenticate(HTTPRequest& request, const HTTPResponse& response)
{
HTTPAuthenticationParams params(response, HTTPAuthenticationParams::PROXY_AUTHENTICATE);
proxyAuthenticate(request, params.get(HTTPAuthenticationParams::NTLM, ""));
}
void HTTPNTLMCredentials::proxyAuthenticate(HTTPRequest& request, const std::string& ntlmChallengeBase64)
{
std::string ntlmMessage = createNTLMMessage(ntlmChallengeBase64);
request.setProxyCredentials(SCHEME, ntlmMessage);
}
void HTTPNTLMCredentials::updateProxyAuthInfo(HTTPRequest& request)
{
request.removeProxyCredentials();
}
std::string HTTPNTLMCredentials::createNTLMMessage(const std::string& responseAuthParams)
{
if (responseAuthParams.empty())
{
std::vector<unsigned char> negotiateBuf;
if (useSSPINTLM())
{
_pNTLMContext = SSPINTLMCredentials::createNTLMContext(_host, SSPINTLMCredentials::SERVICE_HTTP);
negotiateBuf = SSPINTLMCredentials::negotiate(*_pNTLMContext);
}
else
{
NTLMCredentials::NegotiateMessage negotiateMsg;
std::string username;
NTLMCredentials::splitUsername(_username, username, negotiateMsg.domain);
negotiateBuf = NTLMCredentials::formatNegotiateMessage(negotiateMsg);
}
return NTLMCredentials::toBase64(negotiateBuf);
}
else
{
std::vector<unsigned char> buffer = NTLMCredentials::fromBase64(responseAuthParams);
if (buffer.empty()) throw HTTPException("Invalid NTLM challenge");
std::vector<unsigned char> authenticateBuf;
if (useSSPINTLM() && _pNTLMContext)
{
authenticateBuf = SSPINTLMCredentials::authenticate(*_pNTLMContext, buffer);
}
else
{
NTLMCredentials::ChallengeMessage challengeMsg;
if (NTLMCredentials::parseChallengeMessage(&buffer[0], buffer.size(), challengeMsg))
{
if ((challengeMsg.flags & NTLMCredentials::NTLM_FLAG_NEGOTIATE_NTLM2_KEY) == 0)
{
throw HTTPException("Proxy does not support NTLMv2 authentication");
}
std::string username;
std::string domain;
NTLMCredentials::splitUsername(_username, username, domain);
NTLMCredentials::AuthenticateMessage authenticateMsg;
authenticateMsg.flags = challengeMsg.flags;
authenticateMsg.target = challengeMsg.target;
authenticateMsg.username = username;
std::vector<unsigned char> lmNonce = NTLMCredentials::createNonce();
std::vector<unsigned char> ntlmNonce = NTLMCredentials::createNonce();
Poco::UInt64 timestamp = NTLMCredentials::createTimestamp();
std::vector<unsigned char> ntlm2Hash = NTLMCredentials::createNTLMv2Hash(username, challengeMsg.target, _password);
authenticateMsg.lmResponse = NTLMCredentials::createLMv2Response(ntlm2Hash, challengeMsg.challenge, lmNonce);
authenticateMsg.ntlmResponse = NTLMCredentials::createNTLMv2Response(ntlm2Hash, challengeMsg.challenge, ntlmNonce, challengeMsg.targetInfo, timestamp);
authenticateBuf = NTLMCredentials::formatAuthenticateMessage(authenticateMsg);
}
else throw HTTPException("Invalid NTLM challenge");
}
return NTLMCredentials::toBase64(authenticateBuf);
}
}
} } // namespace Poco::Net
+309
View File
@@ -0,0 +1,309 @@
//
// HTTPRequest.cpp
//
// Library: Net
// Package: HTTP
// Module: HTTPRequest
//
// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/HTTPRequest.h"
#include "Poco/Net/NetException.h"
#include "Poco/Net/NameValueCollection.h"
#include "Poco/NumberFormatter.h"
#include "Poco/Ascii.h"
#include "Poco/String.h"
using Poco::NumberFormatter;
namespace Poco {
namespace Net {
const std::string HTTPRequest::HTTP_GET = "GET";
const std::string HTTPRequest::HTTP_HEAD = "HEAD";
const std::string HTTPRequest::HTTP_PUT = "PUT";
const std::string HTTPRequest::HTTP_POST = "POST";
const std::string HTTPRequest::HTTP_OPTIONS = "OPTIONS";
const std::string HTTPRequest::HTTP_DELETE = "DELETE";
const std::string HTTPRequest::HTTP_TRACE = "TRACE";
const std::string HTTPRequest::HTTP_CONNECT = "CONNECT";
const std::string HTTPRequest::HTTP_PATCH = "PATCH";
const std::string HTTPRequest::HOST = "Host";
const std::string HTTPRequest::COOKIE = "Cookie";
const std::string HTTPRequest::AUTHORIZATION = "Authorization";
const std::string HTTPRequest::PROXY_AUTHORIZATION = "Proxy-Authorization";
const std::string HTTPRequest::UPGRADE = "Upgrade";
const std::string HTTPRequest::EXPECT = "Expect";
HTTPRequest::HTTPRequest():
_method(HTTP_GET),
_uri("/")
{
}
HTTPRequest::HTTPRequest(const std::string& version):
HTTPMessage(version),
_method(HTTP_GET),
_uri("/")
{
}
HTTPRequest::HTTPRequest(const std::string& method, const std::string& uri):
_method(method),
_uri(uri)
{
}
HTTPRequest::HTTPRequest(const std::string& method, const std::string& uri, const std::string& version):
HTTPMessage(version),
_method(method),
_uri(uri)
{
}
HTTPRequest::HTTPRequest(const HTTPRequest& other):
HTTPMessage(other),
_method(other._method),
_uri(other._uri)
{
}
HTTPRequest::~HTTPRequest()
{
}
HTTPRequest& HTTPRequest::operator = (const HTTPRequest& other)
{
if (this != &other)
{
HTTPMessage::operator = (other);
_method = other._method;
_uri = other._uri;
}
return *this;
}
void HTTPRequest::setMethod(const std::string& method)
{
_method = method;
}
void HTTPRequest::setURI(const std::string& uri)
{
_uri = uri;
}
void HTTPRequest::setHost(const std::string& host)
{
set(HOST, host);
}
void HTTPRequest::setHost(const std::string& host, Poco::UInt16 port)
{
std::string value;
if (host.find(':') != std::string::npos)
{
// IPv6 address
value.append("[");
value.append(host);
value.append("]");
}
else
{
value.append(host);
}
if (port != 80 && port != 443)
{
value.append(":");
NumberFormatter::append(value, port);
}
setHost(value);
}
const std::string& HTTPRequest::getHost() const
{
return get(HOST);
}
void HTTPRequest::setCookies(const NameValueCollection& cookies)
{
std::string cookie;
cookie.reserve(64);
for (NameValueCollection::ConstIterator it = cookies.begin(); it != cookies.end(); ++it)
{
if (it != cookies.begin())
cookie.append("; ");
cookie.append(it->first);
cookie.append("=");
cookie.append(it->second);
}
add(COOKIE, cookie);
}
void HTTPRequest::getCookies(NameValueCollection& cookies) const
{
NameValueCollection::ConstIterator it = find(COOKIE);
while (it != end() && Poco::icompare(it->first, COOKIE) == 0)
{
splitParameters(it->second.begin(), it->second.end(), cookies);
++it;
}
}
bool HTTPRequest::hasCredentials() const
{
return has(AUTHORIZATION);
}
void HTTPRequest::getCredentials(std::string& scheme, std::string& authInfo) const
{
getCredentials(AUTHORIZATION, scheme, authInfo);
}
void HTTPRequest::setCredentials(const std::string& scheme, const std::string& authInfo)
{
setCredentials(AUTHORIZATION, scheme, authInfo);
}
void HTTPRequest::removeCredentials()
{
erase(AUTHORIZATION);
}
bool HTTPRequest::hasProxyCredentials() const
{
return has(PROXY_AUTHORIZATION);
}
void HTTPRequest::getProxyCredentials(std::string& scheme, std::string& authInfo) const
{
getCredentials(PROXY_AUTHORIZATION, scheme, authInfo);
}
void HTTPRequest::setProxyCredentials(const std::string& scheme, const std::string& authInfo)
{
setCredentials(PROXY_AUTHORIZATION, scheme, authInfo);
}
void HTTPRequest::removeProxyCredentials()
{
erase(PROXY_AUTHORIZATION);
}
void HTTPRequest::write(std::ostream& ostr) const
{
ostr << _method << " " << _uri << " " << getVersion() << "\r\n";
HTTPMessage::write(ostr);
ostr << "\r\n";
}
void HTTPRequest::read(std::istream& istr)
{
static const int eof = std::char_traits<char>::eof();
std::string method;
std::string uri;
std::string version;
method.reserve(16);
uri.reserve(64);
version.reserve(16);
int ch = istr.get();
if (istr.bad()) throw NetException("Error reading HTTP request header");
if (ch == eof) throw NoMessageException();
while (Poco::Ascii::isSpace(ch)) ch = istr.get();
if (ch == eof) throw MessageException("No HTTP request header");
while (!Poco::Ascii::isSpace(ch) && ch != eof && method.length() < MAX_METHOD_LENGTH) { method += (char) ch; ch = istr.get(); }
if (!Poco::Ascii::isSpace(ch)) throw MessageException("HTTP request method invalid or too long");
while (Poco::Ascii::isSpace(ch)) ch = istr.get();
while (!Poco::Ascii::isSpace(ch) && ch != eof && uri.length() < MAX_URI_LENGTH) { uri += (char) ch; ch = istr.get(); }
if (!Poco::Ascii::isSpace(ch)) throw MessageException("HTTP request URI invalid or too long");
while (Poco::Ascii::isSpace(ch)) ch = istr.get();
while (!Poco::Ascii::isSpace(ch) && ch != eof && version.length() < MAX_VERSION_LENGTH) { version += (char) ch; ch = istr.get(); }
if (!Poco::Ascii::isSpace(ch)) throw MessageException("Invalid HTTP version string");
while (ch != '\n' && ch != eof) { ch = istr.get(); }
HTTPMessage::read(istr);
ch = istr.get();
while (ch != '\n' && ch != eof) { ch = istr.get(); }
setMethod(method);
setURI(uri);
setVersion(version);
}
void HTTPRequest::getCredentials(const std::string& header, std::string& scheme, std::string& authInfo) const
{
scheme.clear();
authInfo.clear();
if (has(header))
{
const std::string& auth = get(header);
std::string::const_iterator it = auth.begin();
std::string::const_iterator end = auth.end();
while (it != end && Poco::Ascii::isSpace(*it)) ++it;
while (it != end && !Poco::Ascii::isSpace(*it)) scheme += *it++;
while (it != end && Poco::Ascii::isSpace(*it)) ++it;
while (it != end) authInfo += *it++;
}
else throw NotAuthenticatedException();
}
void HTTPRequest::setCredentials(const std::string& header, const std::string& scheme, const std::string& authInfo)
{
std::string auth(scheme);
auth.append(" ");
auth.append(authInfo);
set(header, auth);
}
bool HTTPRequest::getExpectContinue() const
{
const std::string& expect = get(EXPECT, EMPTY);
return !expect.empty() && icompare(expect, "100-continue") == 0;
}
void HTTPRequest::setExpectContinue(bool expectContinue)
{
if (expectContinue)
set(EXPECT, "100-continue");
else
erase(EXPECT);
}
} } // namespace Poco::Net
+32
View File
@@ -0,0 +1,32 @@
//
// HTTPRequestHandler.cpp
//
// Library: Net
// Package: HTTPServer
// Module: HTTPRequestHandler
//
// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/HTTPRequestHandler.h"
namespace Poco {
namespace Net {
HTTPRequestHandler::HTTPRequestHandler()
{
}
HTTPRequestHandler::~HTTPRequestHandler()
{
}
} } // namespace Poco::Net
+32
View File
@@ -0,0 +1,32 @@
//
// HTTPRequestHandlerFactory.cpp
//
// Library: Net
// Package: HTTPServer
// Module: HTTPRequestHandlerFactory
//
// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/HTTPRequestHandlerFactory.h"
namespace Poco {
namespace Net {
HTTPRequestHandlerFactory::HTTPRequestHandlerFactory()
{
}
HTTPRequestHandlerFactory::~HTTPRequestHandlerFactory()
{
}
} } // namespace Poco::Net
+404
View File
@@ -0,0 +1,404 @@
//
// HTTPResponse.cpp
//
// Library: Net
// Package: HTTP
// Module: HTTPResponse
//
// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/HTTPResponse.h"
#include "Poco/Net/NetException.h"
#include "Poco/NumberFormatter.h"
#include "Poco/NumberParser.h"
#include "Poco/DateTime.h"
#include "Poco/DateTimeFormatter.h"
#include "Poco/DateTimeFormat.h"
#include "Poco/DateTimeParser.h"
#include "Poco/Ascii.h"
#include "Poco/String.h"
using Poco::DateTime;
using Poco::NumberFormatter;
using Poco::NumberParser;
using Poco::DateTimeFormatter;
using Poco::DateTimeFormat;
using Poco::DateTimeParser;
namespace Poco {
namespace Net {
const std::string HTTPResponse::HTTP_REASON_CONTINUE = "Continue";
const std::string HTTPResponse::HTTP_REASON_SWITCHING_PROTOCOLS = "Switching Protocols";
const std::string HTTPResponse::HTTP_REASON_PROCESSING = "Processing";
const std::string HTTPResponse::HTTP_REASON_OK = "OK";
const std::string HTTPResponse::HTTP_REASON_CREATED = "Created";
const std::string HTTPResponse::HTTP_REASON_ACCEPTED = "Accepted";
const std::string HTTPResponse::HTTP_REASON_NONAUTHORITATIVE = "Non-Authoritative Information";
const std::string HTTPResponse::HTTP_REASON_NO_CONTENT = "No Content";
const std::string HTTPResponse::HTTP_REASON_RESET_CONTENT = "Reset Content";
const std::string HTTPResponse::HTTP_REASON_PARTIAL_CONTENT = "Partial Content";
const std::string HTTPResponse::HTTP_REASON_MULTI_STATUS = "Multi Status";
const std::string HTTPResponse::HTTP_REASON_ALREADY_REPORTED = "Already Reported";
const std::string HTTPResponse::HTTP_REASON_IM_USED = "IM Used";
const std::string HTTPResponse::HTTP_REASON_MULTIPLE_CHOICES = "Multiple Choices";
const std::string HTTPResponse::HTTP_REASON_MOVED_PERMANENTLY = "Moved Permanently";
const std::string HTTPResponse::HTTP_REASON_FOUND = "Found";
const std::string HTTPResponse::HTTP_REASON_SEE_OTHER = "See Other";
const std::string HTTPResponse::HTTP_REASON_NOT_MODIFIED = "Not Modified";
const std::string HTTPResponse::HTTP_REASON_USE_PROXY = "Use Proxy";
const std::string HTTPResponse::HTTP_REASON_TEMPORARY_REDIRECT = "Temporary Redirect";
const std::string HTTPResponse::HTTP_REASON_PERMANENT_REDIRECT = "Permanent Redirect";
const std::string HTTPResponse::HTTP_REASON_BAD_REQUEST = "Bad Request";
const std::string HTTPResponse::HTTP_REASON_UNAUTHORIZED = "Unauthorized";
const std::string HTTPResponse::HTTP_REASON_PAYMENT_REQUIRED = "Payment Required";
const std::string HTTPResponse::HTTP_REASON_FORBIDDEN = "Forbidden";
const std::string HTTPResponse::HTTP_REASON_NOT_FOUND = "Not Found";
const std::string HTTPResponse::HTTP_REASON_METHOD_NOT_ALLOWED = "Method Not Allowed";
const std::string HTTPResponse::HTTP_REASON_NOT_ACCEPTABLE = "Not Acceptable";
const std::string HTTPResponse::HTTP_REASON_PROXY_AUTHENTICATION_REQUIRED = "Proxy Authentication Required";
const std::string HTTPResponse::HTTP_REASON_REQUEST_TIMEOUT = "Request Time-out";
const std::string HTTPResponse::HTTP_REASON_CONFLICT = "Conflict";
const std::string HTTPResponse::HTTP_REASON_GONE = "Gone";
const std::string HTTPResponse::HTTP_REASON_LENGTH_REQUIRED = "Length Required";
const std::string HTTPResponse::HTTP_REASON_PRECONDITION_FAILED = "Precondition Failed";
const std::string HTTPResponse::HTTP_REASON_REQUEST_ENTITY_TOO_LARGE = "Request Entity Too Large";
const std::string HTTPResponse::HTTP_REASON_REQUEST_URI_TOO_LONG = "Request-URI Too Large";
const std::string HTTPResponse::HTTP_REASON_UNSUPPORTED_MEDIA_TYPE = "Unsupported Media Type";
const std::string HTTPResponse::HTTP_REASON_REQUESTED_RANGE_NOT_SATISFIABLE = "Requested Range Not Satisfiable";
const std::string HTTPResponse::HTTP_REASON_EXPECTATION_FAILED = "Expectation Failed";
const std::string HTTPResponse::HTTP_REASON_IM_A_TEAPOT = "I'm a Teapot";
const std::string HTTPResponse::HTTP_REASON_ENCHANCE_YOUR_CALM = "Enchance Your Calm";
const std::string HTTPResponse::HTTP_REASON_MISDIRECTED_REQUEST = "Misdirected Request";
const std::string HTTPResponse::HTTP_REASON_UNPROCESSABLE_ENTITY = "Unprocessable Entity";
const std::string HTTPResponse::HTTP_REASON_LOCKED = "Locked";
const std::string HTTPResponse::HTTP_REASON_FAILED_DEPENDENCY = "Failed Dependency";
const std::string HTTPResponse::HTTP_REASON_UPGRADE_REQUIRED = "Upgrade Required";
const std::string HTTPResponse::HTTP_REASON_PRECONDITION_REQUIRED = "Precondition Required";
const std::string HTTPResponse::HTTP_REASON_TOO_MANY_REQUESTS = "Too Many Requests";
const std::string HTTPResponse::HTTP_REASON_REQUEST_HEADER_FIELDS_TOO_LARGE = "Request Header Fields Too Large";
const std::string HTTPResponse::HTTP_REASON_UNAVAILABLE_FOR_LEGAL_REASONS = "Unavailable For Legal Reasons";
const std::string HTTPResponse::HTTP_REASON_INTERNAL_SERVER_ERROR = "Internal Server Error";
const std::string HTTPResponse::HTTP_REASON_NOT_IMPLEMENTED = "Not Implemented";
const std::string HTTPResponse::HTTP_REASON_BAD_GATEWAY = "Bad Gateway";
const std::string HTTPResponse::HTTP_REASON_SERVICE_UNAVAILABLE = "Service Unavailable";
const std::string HTTPResponse::HTTP_REASON_GATEWAY_TIMEOUT = "Gateway Time-Out";
const std::string HTTPResponse::HTTP_REASON_VERSION_NOT_SUPPORTED = "HTTP Version Not Supported";
const std::string HTTPResponse::HTTP_REASON_VARIANT_ALSO_NEGOTIATES = "Variant Also Negotiates";
const std::string HTTPResponse::HTTP_REASON_INSUFFICIENT_STORAGE = "Insufficient Storage";
const std::string HTTPResponse::HTTP_REASON_LOOP_DETECTED = "Loop Detected";
const std::string HTTPResponse::HTTP_REASON_NOT_EXTENDED = "Not Extended";
const std::string HTTPResponse::HTTP_REASON_NETWORK_AUTHENTICATION_REQUIRED = "Network Authentication Required";
const std::string HTTPResponse::HTTP_REASON_UNKNOWN = "???";
const std::string HTTPResponse::DATE = "Date";
const std::string HTTPResponse::SET_COOKIE = "Set-Cookie";
HTTPResponse::HTTPResponse():
_status(HTTP_OK),
_reason(getReasonForStatus(HTTP_OK))
{
}
HTTPResponse::HTTPResponse(HTTPStatus status, const std::string& reason):
_status(status),
_reason(reason)
{
}
HTTPResponse::HTTPResponse(const std::string& version, HTTPStatus status, const std::string& reason):
HTTPMessage(version),
_status(status),
_reason(reason)
{
}
HTTPResponse::HTTPResponse(HTTPStatus status):
_status(status),
_reason(getReasonForStatus(status))
{
}
HTTPResponse::HTTPResponse(const std::string& version, HTTPStatus status):
HTTPMessage(version),
_status(status),
_reason(getReasonForStatus(status))
{
}
HTTPResponse::HTTPResponse(const HTTPResponse& other):
HTTPMessage(other),
_status(other._status),
_reason(other._reason)
{
}
HTTPResponse::~HTTPResponse()
{
}
HTTPResponse& HTTPResponse::operator = (const HTTPResponse& other)
{
if (this != &other)
{
HTTPMessage::operator = (other);
_status = other._status;
_reason = other._reason;
}
return *this;
}
void HTTPResponse::setStatus(HTTPStatus status)
{
_status = status;
}
void HTTPResponse::setStatus(const std::string& status)
{
setStatus((HTTPStatus) NumberParser::parse(status));
}
void HTTPResponse::setReason(const std::string& reason)
{
_reason = reason;
}
void HTTPResponse::setStatusAndReason(HTTPStatus status, const std::string& reason)
{
_status = status;
_reason = reason;
}
void HTTPResponse::setStatusAndReason(HTTPStatus status)
{
setStatusAndReason(status, getReasonForStatus(status));
}
void HTTPResponse::setDate(const Poco::Timestamp& dateTime)
{
set(DATE, DateTimeFormatter::format(dateTime, DateTimeFormat::HTTP_FORMAT));
}
Poco::Timestamp HTTPResponse::getDate() const
{
const std::string& dateTime = get(DATE);
int tzd;
return DateTimeParser::parse(dateTime, tzd).timestamp();
}
void HTTPResponse::addCookie(const HTTPCookie& cookie)
{
add(SET_COOKIE, cookie.toString());
}
void HTTPResponse::getCookies(std::vector<HTTPCookie>& cookies) const
{
cookies.clear();
NameValueCollection::ConstIterator it = find(SET_COOKIE);
while (it != end() && Poco::icompare(it->first, SET_COOKIE) == 0)
{
NameValueCollection nvc;
splitParameters(it->second.begin(), it->second.end(), nvc);
cookies.push_back(HTTPCookie(nvc));
++it;
}
}
void HTTPResponse::write(std::ostream& ostr) const
{
ostr << getVersion() << " " << static_cast<int>(_status) << " " << _reason << "\r\n";
HTTPMessage::write(ostr);
ostr << "\r\n";
}
void HTTPResponse::read(std::istream& istr)
{
static const int eof = std::char_traits<char>::eof();
std::string version;
std::string status;
std::string reason;
int ch = istr.get();
if (istr.bad()) throw NetException("Error reading HTTP response header");
if (ch == eof) throw NoMessageException();
while (Poco::Ascii::isSpace(ch)) ch = istr.get();
if (ch == eof) throw MessageException("No HTTP response header");
while (!Poco::Ascii::isSpace(ch) && ch != eof && version.length() < MAX_VERSION_LENGTH) { version += (char) ch; ch = istr.get(); }
if (!Poco::Ascii::isSpace(ch)) throw MessageException("Invalid HTTP version string");
while (Poco::Ascii::isSpace(ch)) ch = istr.get();
while (!Poco::Ascii::isSpace(ch) && ch != eof && status.length() < MAX_STATUS_LENGTH) { status += (char) ch; ch = istr.get(); }
if (!Poco::Ascii::isSpace(ch)) throw MessageException("Invalid HTTP status code");
while (Poco::Ascii::isSpace(ch) && ch != '\r' && ch != '\n' && ch != eof) ch = istr.get();
while (ch != '\r' && ch != '\n' && ch != eof && reason.length() < MAX_REASON_LENGTH) { reason += (char) ch; ch = istr.get(); }
if (!Poco::Ascii::isSpace(ch)) throw MessageException("HTTP reason string too long");
if (ch == '\r') ch = istr.get();
if (ch != '\n') throw MessageException("Unterminated HTTP response line");
HTTPMessage::read(istr);
ch = istr.get();
while (ch != '\n' && ch != eof) { ch = istr.get(); }
setVersion(version);
setStatus(status);
setReason(reason);
}
const std::string& HTTPResponse::getReasonForStatus(HTTPStatus status)
{
switch (status)
{
case HTTP_CONTINUE:
return HTTP_REASON_CONTINUE;
case HTTP_SWITCHING_PROTOCOLS:
return HTTP_REASON_SWITCHING_PROTOCOLS;
case HTTP_PROCESSING:
return HTTP_REASON_PROCESSING;
case HTTP_OK:
return HTTP_REASON_OK;
case HTTP_CREATED:
return HTTP_REASON_CREATED;
case HTTP_ACCEPTED:
return HTTP_REASON_ACCEPTED;
case HTTP_NONAUTHORITATIVE:
return HTTP_REASON_NONAUTHORITATIVE;
case HTTP_NO_CONTENT:
return HTTP_REASON_NO_CONTENT;
case HTTP_RESET_CONTENT:
return HTTP_REASON_RESET_CONTENT;
case HTTP_PARTIAL_CONTENT:
return HTTP_REASON_PARTIAL_CONTENT;
case HTTP_MULTI_STATUS:
return HTTP_REASON_MULTI_STATUS;
case HTTP_ALREADY_REPORTED:
return HTTP_REASON_ALREADY_REPORTED;
case HTTP_IM_USED:
return HTTP_REASON_IM_USED;
case HTTP_MULTIPLE_CHOICES:
return HTTP_REASON_MULTIPLE_CHOICES;
case HTTP_MOVED_PERMANENTLY:
return HTTP_REASON_MOVED_PERMANENTLY;
case HTTP_FOUND:
return HTTP_REASON_FOUND;
case HTTP_SEE_OTHER:
return HTTP_REASON_SEE_OTHER;
case HTTP_NOT_MODIFIED:
return HTTP_REASON_NOT_MODIFIED;
case HTTP_USE_PROXY:
return HTTP_REASON_USE_PROXY;
case HTTP_TEMPORARY_REDIRECT:
return HTTP_REASON_TEMPORARY_REDIRECT;
case HTTP_BAD_REQUEST:
return HTTP_REASON_BAD_REQUEST;
case HTTP_UNAUTHORIZED:
return HTTP_REASON_UNAUTHORIZED;
case HTTP_PAYMENT_REQUIRED:
return HTTP_REASON_PAYMENT_REQUIRED;
case HTTP_FORBIDDEN:
return HTTP_REASON_FORBIDDEN;
case HTTP_NOT_FOUND:
return HTTP_REASON_NOT_FOUND;
case HTTP_METHOD_NOT_ALLOWED:
return HTTP_REASON_METHOD_NOT_ALLOWED;
case HTTP_NOT_ACCEPTABLE:
return HTTP_REASON_NOT_ACCEPTABLE;
case HTTP_PROXY_AUTHENTICATION_REQUIRED:
return HTTP_REASON_PROXY_AUTHENTICATION_REQUIRED;
case HTTP_REQUEST_TIMEOUT:
return HTTP_REASON_REQUEST_TIMEOUT;
case HTTP_CONFLICT:
return HTTP_REASON_CONFLICT;
case HTTP_GONE:
return HTTP_REASON_GONE;
case HTTP_LENGTH_REQUIRED:
return HTTP_REASON_LENGTH_REQUIRED;
case HTTP_PRECONDITION_FAILED:
return HTTP_REASON_PRECONDITION_FAILED;
case HTTP_REQUEST_ENTITY_TOO_LARGE:
return HTTP_REASON_REQUEST_ENTITY_TOO_LARGE;
case HTTP_REQUEST_URI_TOO_LONG:
return HTTP_REASON_REQUEST_URI_TOO_LONG;
case HTTP_UNSUPPORTED_MEDIA_TYPE:
return HTTP_REASON_UNSUPPORTED_MEDIA_TYPE;
case HTTP_REQUESTED_RANGE_NOT_SATISFIABLE:
return HTTP_REASON_REQUESTED_RANGE_NOT_SATISFIABLE;
case HTTP_EXPECTATION_FAILED:
return HTTP_REASON_EXPECTATION_FAILED;
case HTTP_IM_A_TEAPOT:
return HTTP_REASON_IM_A_TEAPOT;
case HTTP_ENCHANCE_YOUR_CALM:
return HTTP_REASON_ENCHANCE_YOUR_CALM;
case HTTP_MISDIRECTED_REQUEST:
return HTTP_REASON_MISDIRECTED_REQUEST;
case HTTP_UNPROCESSABLE_ENTITY:
return HTTP_REASON_UNPROCESSABLE_ENTITY;
case HTTP_LOCKED:
return HTTP_REASON_LOCKED;
case HTTP_FAILED_DEPENDENCY:
return HTTP_REASON_FAILED_DEPENDENCY;
case HTTP_UPGRADE_REQUIRED:
return HTTP_REASON_UPGRADE_REQUIRED;
case HTTP_PRECONDITION_REQUIRED:
return HTTP_REASON_PRECONDITION_REQUIRED;
case HTTP_TOO_MANY_REQUESTS:
return HTTP_REASON_TOO_MANY_REQUESTS;
case HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE:
return HTTP_REASON_REQUEST_HEADER_FIELDS_TOO_LARGE;
case HTTP_UNAVAILABLE_FOR_LEGAL_REASONS:
return HTTP_REASON_UNAVAILABLE_FOR_LEGAL_REASONS;
case HTTP_INTERNAL_SERVER_ERROR:
return HTTP_REASON_INTERNAL_SERVER_ERROR;
case HTTP_NOT_IMPLEMENTED:
return HTTP_REASON_NOT_IMPLEMENTED;
case HTTP_BAD_GATEWAY:
return HTTP_REASON_BAD_GATEWAY;
case HTTP_SERVICE_UNAVAILABLE:
return HTTP_REASON_SERVICE_UNAVAILABLE;
case HTTP_GATEWAY_TIMEOUT:
return HTTP_REASON_GATEWAY_TIMEOUT;
case HTTP_VERSION_NOT_SUPPORTED:
return HTTP_REASON_VERSION_NOT_SUPPORTED;
case HTTP_VARIANT_ALSO_NEGOTIATES:
return HTTP_REASON_VARIANT_ALSO_NEGOTIATES;
case HTTP_INSUFFICIENT_STORAGE:
return HTTP_REASON_INSUFFICIENT_STORAGE;
case HTTP_LOOP_DETECTED:
return HTTP_REASON_LOOP_DETECTED;
case HTTP_NOT_EXTENDED:
return HTTP_REASON_NOT_EXTENDED;
case HTTP_NETWORK_AUTHENTICATION_REQUIRED:
return HTTP_REASON_NETWORK_AUTHENTICATION_REQUIRED;
default:
return HTTP_REASON_UNKNOWN;
}
}
} } // namespace Poco::Net
+56
View File
@@ -0,0 +1,56 @@
//
// HTTPServer.cpp
//
// Library: Net
// Package: HTTPServer
// Module: HTTPServer
//
// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/HTTPServer.h"
#include "Poco/Net/HTTPServerConnectionFactory.h"
namespace Poco {
namespace Net {
HTTPServer::HTTPServer(HTTPRequestHandlerFactory::Ptr pFactory, Poco::UInt16 portNumber, HTTPServerParams::Ptr pParams):
TCPServer(new HTTPServerConnectionFactory(pParams, pFactory), portNumber, pParams),
_pFactory(pFactory)
{
}
HTTPServer::HTTPServer(HTTPRequestHandlerFactory::Ptr pFactory, const ServerSocket& socket, HTTPServerParams::Ptr pParams):
TCPServer(new HTTPServerConnectionFactory(pParams, pFactory), socket, pParams),
_pFactory(pFactory)
{
}
HTTPServer::HTTPServer(HTTPRequestHandlerFactory::Ptr pFactory, Poco::ThreadPool& threadPool, const ServerSocket& socket, HTTPServerParams::Ptr pParams):
TCPServer(new HTTPServerConnectionFactory(pParams, pFactory), threadPool, socket, pParams),
_pFactory(pFactory)
{
}
HTTPServer::~HTTPServer()
{
}
void HTTPServer::stopAll(bool abortCurrent)
{
stop();
_pFactory->serverStopped(this, abortCurrent);
}
} } // namespace Poco::Net
+176
View File
@@ -0,0 +1,176 @@
//
// HTTPServerConnection.cpp
//
// Library: Net
// Package: HTTPServer
// Module: HTTPServerConnection
//
// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/HTTPServerConnection.h"
#include "Poco/Net/HTTPServerSession.h"
#include "Poco/Net/HTTPServerRequestImpl.h"
#include "Poco/Net/HTTPServerResponseImpl.h"
#include "Poco/Net/HTTPRequestHandler.h"
#include "Poco/Net/HTTPRequestHandlerFactory.h"
#include "Poco/Net/NetException.h"
#include "Poco/NumberFormatter.h"
#include "Poco/Timestamp.h"
#include "Poco/Delegate.h"
#include <memory>
namespace Poco {
namespace Net {
HTTPServerConnection::HTTPServerConnection(const StreamSocket& socket, HTTPServerParams::Ptr pParams, HTTPRequestHandlerFactory::Ptr pFactory):
TCPServerConnection(socket),
_pParams(pParams),
_pFactory(pFactory),
_stopped(false)
{
poco_check_ptr (pFactory);
_pFactory->serverStopped += Poco::delegate(this, &HTTPServerConnection::onServerStopped);
}
HTTPServerConnection::~HTTPServerConnection()
{
try
{
_pFactory->serverStopped -= Poco::delegate(this, &HTTPServerConnection::onServerStopped);
}
catch (...)
{
poco_unexpected();
}
}
void HTTPServerConnection::run()
{
std::string server = _pParams->getSoftwareVersion();
HTTPServerSession session(socket(), _pParams);
while (!_stopped && session.hasMoreRequests())
{
try
{
Poco::FastMutex::ScopedLock lock(_mutex);
if (!_stopped)
{
HTTPServerResponseImpl response(session);
HTTPServerRequestImpl request(response, session, _pParams);
Poco::Timestamp now;
response.setDate(now);
response.setVersion(request.getVersion());
response.setKeepAlive(_pParams->getKeepAlive() && request.getKeepAlive() && session.canKeepAlive());
if (!server.empty())
response.set("Server", server);
try
{
std::unique_ptr<HTTPRequestHandler> pHandler(_pFactory->createRequestHandler(request));
if (pHandler.get())
{
if (request.getExpectContinue() && response.getStatus() == HTTPResponse::HTTP_OK)
response.sendContinue();
pHandler->handleRequest(request, response);
session.setKeepAlive(_pParams->getKeepAlive() && response.getKeepAlive() && session.canKeepAlive());
}
else sendErrorResponse(session, HTTPResponse::HTTP_NOT_IMPLEMENTED);
}
catch (Poco::Exception&)
{
if (!response.sent())
{
try
{
sendErrorResponse(session, HTTPResponse::HTTP_INTERNAL_SERVER_ERROR);
}
catch (...)
{
}
}
throw;
}
}
}
catch (NoMessageException&)
{
break;
}
catch (MessageException&)
{
sendErrorResponse(session, HTTPResponse::HTTP_BAD_REQUEST);
}
catch (Poco::Exception&)
{
if (session.networkException())
{
session.networkException()->rethrow();
}
else throw;
}
}
}
void HTTPServerConnection::sendErrorResponse(HTTPServerSession& session, HTTPResponse::HTTPStatus status)
{
HTTPServerResponseImpl response(session);
response.setVersion(HTTPMessage::HTTP_1_1);
response.setStatusAndReason(status);
response.setKeepAlive(false);
response.send();
session.setKeepAlive(false);
}
void HTTPServerConnection::onServerStopped(const bool& abortCurrent)
{
_stopped = true;
if (abortCurrent)
{
try
{
// Note: On Windows, select() will not return if one of its socket is being
// shut down. Therefore we have to call close(), which works better.
// On other platforms, we do the more graceful thing.
#if defined(_WIN32)
socket().close();
#else
socket().shutdown();
#endif
}
catch (...)
{
}
}
else
{
Poco::FastMutex::ScopedLock lock(_mutex);
try
{
#if defined(_WIN32)
socket().close();
#else
socket().shutdown();
#endif
}
catch (...)
{
}
}
}
} } // namespace Poco::Net
+43
View File
@@ -0,0 +1,43 @@
//
// HTTPServerConnectionFactory.cpp
//
// Library: Net
// Package: HTTPServer
// Module: HTTPServerConnectionFactory
//
// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/HTTPServerConnectionFactory.h"
#include "Poco/Net/HTTPServerConnection.h"
#include "Poco/Net/HTTPRequestHandlerFactory.h"
namespace Poco {
namespace Net {
HTTPServerConnectionFactory::HTTPServerConnectionFactory(HTTPServerParams::Ptr pParams, HTTPRequestHandlerFactory::Ptr pFactory):
_pParams(pParams),
_pFactory(pFactory)
{
poco_check_ptr (pFactory);
}
HTTPServerConnectionFactory::~HTTPServerConnectionFactory()
{
}
TCPServerConnection* HTTPServerConnectionFactory::createConnection(const StreamSocket& socket)
{
return new HTTPServerConnection(socket, _pParams, _pFactory);
}
} } // namespace Poco::Net
+73
View File
@@ -0,0 +1,73 @@
//
// HTTPServerParams.cpp
//
// Library: Net
// Package: HTTPServer
// Module: HTTPServerParams
//
// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/HTTPServerParams.h"
namespace Poco {
namespace Net {
HTTPServerParams::HTTPServerParams():
_timeout(60000000),
_keepAlive(true),
_maxKeepAliveRequests(0),
_keepAliveTimeout(15000000)
{
}
HTTPServerParams::~HTTPServerParams()
{
}
void HTTPServerParams::setServerName(const std::string& serverName)
{
_serverName = serverName;
}
void HTTPServerParams::setSoftwareVersion(const std::string& softwareVersion)
{
_softwareVersion = softwareVersion;
}
void HTTPServerParams::setTimeout(const Poco::Timespan& timeout)
{
_timeout = timeout;
}
void HTTPServerParams::setKeepAlive(bool keepAlive)
{
_keepAlive = keepAlive;
}
void HTTPServerParams::setKeepAliveTimeout(const Poco::Timespan& timeout)
{
_keepAliveTimeout = timeout;
}
void HTTPServerParams::setMaxKeepAliveRequests(int maxKeepAliveRequests)
{
poco_assert (maxKeepAliveRequests >= 0);
_maxKeepAliveRequests = maxKeepAliveRequests;
}
} } // namespace Poco::Net
+32
View File
@@ -0,0 +1,32 @@
//
// HTTPServerRequest.cpp
//
// Library: Net
// Package: HTTPServer
// Module: HTTPServerRequest
//
// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/HTTPServerRequest.h"
namespace Poco {
namespace Net {
HTTPServerRequest::HTTPServerRequest()
{
}
HTTPServerRequest::~HTTPServerRequest()
{
}
} } // namespace Poco::Net
+88
View File
@@ -0,0 +1,88 @@
//
// HTTPServerRequestImpl.cpp
//
// Library: Net
// Package: HTTPServer
// Module: HTTPServerRequestImpl
//
// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/HTTPServerRequestImpl.h"
#include "Poco/Net/HTTPServerResponseImpl.h"
#include "Poco/Net/HTTPServerSession.h"
#include "Poco/Net/HTTPHeaderStream.h"
#include "Poco/Net/HTTPStream.h"
#include "Poco/Net/HTTPFixedLengthStream.h"
#include "Poco/Net/HTTPChunkedStream.h"
#include "Poco/Net/HTTPServerParams.h"
#include "Poco/Net/StreamSocket.h"
#include "Poco/String.h"
using Poco::icompare;
namespace Poco {
namespace Net {
HTTPServerRequestImpl::HTTPServerRequestImpl(HTTPServerResponseImpl& response, HTTPServerSession& session, HTTPServerParams* pParams):
_response(response),
_session(session),
_pStream(0),
_pParams(pParams, true)
{
response.attachRequest(this);
HTTPHeaderInputStream hs(session);
read(hs);
// Now that we know socket is still connected, obtain addresses
_clientAddress = session.clientAddress();
_serverAddress = session.serverAddress();
if (getChunkedTransferEncoding())
_pStream = new HTTPChunkedInputStream(session);
else if (hasContentLength())
#if defined(POCO_HAVE_INT64)
_pStream = new HTTPFixedLengthInputStream(session, getContentLength64());
#else
_pStream = new HTTPFixedLengthInputStream(session, getContentLength());
#endif
else if (getMethod() == HTTPRequest::HTTP_GET || getMethod() == HTTPRequest::HTTP_HEAD || getMethod() == HTTPRequest::HTTP_DELETE)
_pStream = new HTTPFixedLengthInputStream(session, 0);
else
_pStream = new HTTPInputStream(session);
}
HTTPServerRequestImpl::~HTTPServerRequestImpl()
{
delete _pStream;
}
bool HTTPServerRequestImpl::secure() const
{
return _session.socket().secure();
}
StreamSocket& HTTPServerRequestImpl::socket()
{
return _session.socket();
}
StreamSocket HTTPServerRequestImpl::detachSocket()
{
return _session.detachSocket();
}
} } // namespace Poco::Net
+32
View File
@@ -0,0 +1,32 @@
//
// HTTPServerResponse.cpp
//
// Library: Net
// Package: HTTPServer
// Module: HTTPServerResponse
//
// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/HTTPServerResponse.h"
namespace Poco {
namespace Net {
HTTPServerResponse::HTTPServerResponse()
{
}
HTTPServerResponse::~HTTPServerResponse()
{
}
} } // namespace Poco::Net
+181
View File
@@ -0,0 +1,181 @@
//
// HTTPServerResponseImpl.cpp
//
// Library: Net
// Package: HTTPServer
// Module: HTTPServerResponseImpl
//
// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/HTTPServerResponseImpl.h"
#include "Poco/Net/HTTPServerRequestImpl.h"
#include "Poco/Net/HTTPServerSession.h"
#include "Poco/Net/HTTPHeaderStream.h"
#include "Poco/Net/HTTPStream.h"
#include "Poco/Net/HTTPFixedLengthStream.h"
#include "Poco/Net/HTTPChunkedStream.h"
#include "Poco/File.h"
#include "Poco/Timestamp.h"
#include "Poco/NumberFormatter.h"
#include "Poco/StreamCopier.h"
#include "Poco/CountingStream.h"
#include "Poco/Exception.h"
#include "Poco/FileStream.h"
#include "Poco/DateTimeFormatter.h"
#include "Poco/DateTimeFormat.h"
using Poco::File;
using Poco::Timestamp;
using Poco::NumberFormatter;
using Poco::StreamCopier;
using Poco::OpenFileException;
using Poco::DateTimeFormatter;
using Poco::DateTimeFormat;
namespace Poco {
namespace Net {
HTTPServerResponseImpl::HTTPServerResponseImpl(HTTPServerSession& session):
_session(session),
_pRequest(0),
_pStream(0)
{
}
HTTPServerResponseImpl::~HTTPServerResponseImpl()
{
delete _pStream;
}
void HTTPServerResponseImpl::sendContinue()
{
HTTPHeaderOutputStream hs(_session);
hs << getVersion() << " 100 Continue\r\n\r\n";
}
std::ostream& HTTPServerResponseImpl::send()
{
poco_assert (!_pStream);
if ((_pRequest && _pRequest->getMethod() == HTTPRequest::HTTP_HEAD) ||
getStatus() < 200 ||
getStatus() == HTTPResponse::HTTP_NO_CONTENT ||
getStatus() == HTTPResponse::HTTP_NOT_MODIFIED)
{
Poco::CountingOutputStream cs;
write(cs);
_pStream = new HTTPFixedLengthOutputStream(_session, cs.chars());
write(*_pStream);
}
else if (getChunkedTransferEncoding())
{
HTTPHeaderOutputStream hs(_session);
write(hs);
_pStream = new HTTPChunkedOutputStream(_session);
}
else if (hasContentLength())
{
Poco::CountingOutputStream cs;
write(cs);
#if defined(POCO_HAVE_INT64)
_pStream = new HTTPFixedLengthOutputStream(_session, getContentLength64() + cs.chars());
#else
_pStream = new HTTPFixedLengthOutputStream(_session, getContentLength() + cs.chars());
#endif
write(*_pStream);
}
else
{
_pStream = new HTTPOutputStream(_session);
setKeepAlive(false);
write(*_pStream);
}
return *_pStream;
}
void HTTPServerResponseImpl::sendFile(const std::string& path, const std::string& mediaType)
{
poco_assert (!_pStream);
File f(path);
Timestamp dateTime = f.getLastModified();
File::FileSize length = f.getSize();
set("Last-Modified", DateTimeFormatter::format(dateTime, DateTimeFormat::HTTP_FORMAT));
#if defined(POCO_HAVE_INT64)
setContentLength64(length);
#else
setContentLength(static_cast<int>(length));
#endif
setContentType(mediaType);
setChunkedTransferEncoding(false);
Poco::FileInputStream istr(path);
if (istr.good())
{
_pStream = new HTTPHeaderOutputStream(_session);
write(*_pStream);
if (_pRequest && _pRequest->getMethod() != HTTPRequest::HTTP_HEAD)
{
StreamCopier::copyStream(istr, *_pStream);
}
}
else throw OpenFileException(path);
}
void HTTPServerResponseImpl::sendBuffer(const void* pBuffer, std::size_t length)
{
poco_assert (!_pStream);
setContentLength(static_cast<int>(length));
setChunkedTransferEncoding(false);
_pStream = new HTTPHeaderOutputStream(_session);
write(*_pStream);
if (_pRequest && _pRequest->getMethod() != HTTPRequest::HTTP_HEAD)
{
_pStream->write(static_cast<const char*>(pBuffer), static_cast<std::streamsize>(length));
}
}
void HTTPServerResponseImpl::redirect(const std::string& uri, HTTPStatus status)
{
poco_assert (!_pStream);
setContentLength(0);
setChunkedTransferEncoding(false);
setStatusAndReason(status);
set("Location", uri);
_pStream = new HTTPHeaderOutputStream(_session);
write(*_pStream);
}
void HTTPServerResponseImpl::requireAuthentication(const std::string& realm)
{
poco_assert (!_pStream);
setStatusAndReason(HTTPResponse::HTTP_UNAUTHORIZED);
std::string auth("Basic realm=\"");
auth.append(realm);
auth.append("\"");
set("WWW-Authenticate", auth);
}
} } // namespace Poco::Net
+70
View File
@@ -0,0 +1,70 @@
//
// HTTPServerSession.cpp
//
// Library: Net
// Package: HTTPServer
// Module: HTTPServerSession
//
// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/HTTPServerSession.h"
namespace Poco {
namespace Net {
HTTPServerSession::HTTPServerSession(const StreamSocket& socket, HTTPServerParams::Ptr pParams):
HTTPSession(socket, pParams->getKeepAlive()),
_firstRequest(true),
_keepAliveTimeout(pParams->getKeepAliveTimeout()),
_maxKeepAliveRequests(pParams->getMaxKeepAliveRequests())
{
setTimeout(pParams->getTimeout());
this->socket().setReceiveTimeout(pParams->getTimeout());
}
HTTPServerSession::~HTTPServerSession()
{
}
bool HTTPServerSession::hasMoreRequests()
{
if (!socket().impl()->initialized()) return false;
if (_firstRequest)
{
_firstRequest = false;
--_maxKeepAliveRequests;
return socket().poll(getTimeout(), Socket::SELECT_READ);
}
else if (_maxKeepAliveRequests != 0 && getKeepAlive())
{
if (_maxKeepAliveRequests > 0)
--_maxKeepAliveRequests;
return buffered() > 0 || socket().poll(_keepAliveTimeout, Socket::SELECT_READ);
}
else return false;
}
SocketAddress HTTPServerSession::clientAddress()
{
return socket().peerAddress();
}
SocketAddress HTTPServerSession::serverAddress()
{
return socket().address();
}
} } // namespace Poco::Net
+261
View File
@@ -0,0 +1,261 @@
//
// HTTPSession.cpp
//
// Library: Net
// Package: HTTP
// Module: HTTPSession
//
// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/HTTPSession.h"
#include "Poco/Net/HTTPBufferAllocator.h"
#include "Poco/Net/NetException.h"
#include <cstring>
using Poco::TimeoutException;
namespace Poco {
namespace Net {
HTTPSession::HTTPSession():
_pBuffer(0),
_pCurrent(0),
_pEnd(0),
_keepAlive(false),
_connectionTimeout(HTTP_DEFAULT_CONNECTION_TIMEOUT),
_receiveTimeout(HTTP_DEFAULT_TIMEOUT),
_sendTimeout(HTTP_DEFAULT_TIMEOUT),
_pException(0)
{
}
HTTPSession::HTTPSession(const StreamSocket& socket):
_socket(socket),
_pBuffer(0),
_pCurrent(0),
_pEnd(0),
_keepAlive(false),
_connectionTimeout(HTTP_DEFAULT_CONNECTION_TIMEOUT),
_receiveTimeout(HTTP_DEFAULT_TIMEOUT),
_sendTimeout(HTTP_DEFAULT_TIMEOUT),
_pException(0)
{
}
HTTPSession::HTTPSession(const StreamSocket& socket, bool keepAlive):
_socket(socket),
_pBuffer(0),
_pCurrent(0),
_pEnd(0),
_keepAlive(keepAlive),
_connectionTimeout(HTTP_DEFAULT_CONNECTION_TIMEOUT),
_receiveTimeout(HTTP_DEFAULT_TIMEOUT),
_sendTimeout(HTTP_DEFAULT_TIMEOUT),
_pException(0)
{
}
HTTPSession::~HTTPSession()
{
try
{
if (_pBuffer) HTTPBufferAllocator::deallocate(_pBuffer, HTTPBufferAllocator::BUFFER_SIZE);
}
catch (...)
{
poco_unexpected();
}
try
{
close();
}
catch (...)
{
}
delete _pException;
}
void HTTPSession::setKeepAlive(bool keepAlive)
{
_keepAlive = keepAlive;
}
void HTTPSession::setTimeout(const Poco::Timespan& timeout)
{
setTimeout(timeout, timeout, timeout);
}
void HTTPSession::setTimeout(const Poco::Timespan& connectionTimeout, const Poco::Timespan& sendTimeout, const Poco::Timespan& receiveTimeout)
{
_connectionTimeout = connectionTimeout;
_sendTimeout = sendTimeout;
_receiveTimeout = receiveTimeout;
}
int HTTPSession::get()
{
if (_pCurrent == _pEnd)
refill();
if (_pCurrent < _pEnd)
return *_pCurrent++;
else
return std::char_traits<char>::eof();
}
int HTTPSession::peek()
{
if (_pCurrent == _pEnd)
refill();
if (_pCurrent < _pEnd)
return *_pCurrent;
else
return std::char_traits<char>::eof();
}
int HTTPSession::read(char* buffer, std::streamsize length)
{
if (_pCurrent < _pEnd)
{
int n = (int) (_pEnd - _pCurrent);
if (n > length) n = (int) length;
std::memcpy(buffer, _pCurrent, n);
_pCurrent += n;
return n;
}
else return receive(buffer, (int) length);
}
int HTTPSession::write(const char* buffer, std::streamsize length)
{
try
{
return _socket.sendBytes(buffer, (int) length);
}
catch (Poco::Exception& exc)
{
setException(exc);
throw;
}
}
int HTTPSession::receive(char* buffer, int length)
{
try
{
return _socket.receiveBytes(buffer, length);
}
catch (Poco::Exception& exc)
{
setException(exc);
throw;
}
}
void HTTPSession::refill()
{
if (!_pBuffer)
{
_pBuffer = HTTPBufferAllocator::allocate(HTTPBufferAllocator::BUFFER_SIZE);
}
_pCurrent = _pEnd = _pBuffer;
int n = receive(_pBuffer, HTTPBufferAllocator::BUFFER_SIZE);
_pEnd += n;
}
bool HTTPSession::connected() const
{
return _socket.impl()->initialized();
}
void HTTPSession::connect(const SocketAddress& address)
{
_socket.connect(address, _connectionTimeout);
_socket.setReceiveTimeout(_receiveTimeout);
_socket.setSendTimeout(_sendTimeout);
_socket.setNoDelay(true);
// There may be leftover data from a previous (failed) request in the buffer,
// so we clear it.
_pCurrent = _pEnd = _pBuffer;
}
void HTTPSession::abort()
{
_socket.shutdown();
close();
}
void HTTPSession::close()
{
_socket.close();
}
void HTTPSession::setException(const Poco::Exception& exc)
{
delete _pException;
_pException = exc.clone();
}
void HTTPSession::clearException()
{
delete _pException;
_pException = 0;
}
StreamSocket HTTPSession::detachSocket()
{
StreamSocket oldSocket(_socket);
StreamSocket newSocket;
_socket = newSocket;
return oldSocket;
}
void HTTPSession::attachSocket(const StreamSocket& socket)
{
_socket = socket;
}
void HTTPSession::attachSessionData(const Poco::Any& data)
{
_data = data;
}
void HTTPSession::drainBuffer(Poco::Buffer<char>& buffer)
{
buffer.assign(_pCurrent, static_cast<std::size_t>(_pEnd - _pCurrent));
_pCurrent = _pEnd;
}
} } // namespace Poco::Net
+146
View File
@@ -0,0 +1,146 @@
//
// HTTPSessionFactory.cpp
//
// Library: Net
// Package: HTTPClient
// Module: HTTPSessionFactory
//
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/HTTPSessionFactory.h"
#include "Poco/Net/HTTPSessionInstantiator.h"
#include "Poco/Exception.h"
using Poco::SingletonHolder;
using Poco::FastMutex;
using Poco::NotFoundException;
using Poco::ExistsException;
namespace Poco {
namespace Net {
HTTPSessionFactory::HTTPSessionFactory():
_proxyPort(0)
{
}
HTTPSessionFactory::HTTPSessionFactory(const std::string& proxyHost, Poco::UInt16 proxyPort):
_proxyHost(proxyHost),
_proxyPort(proxyPort)
{
}
HTTPSessionFactory::~HTTPSessionFactory()
{
for (auto& p: _instantiators)
{
delete p.second.pIn;
}
}
void HTTPSessionFactory::registerProtocol(const std::string& protocol, HTTPSessionInstantiator* pSessionInstantiator)
{
poco_assert_dbg(pSessionInstantiator);
FastMutex::ScopedLock lock(_mutex);
std::pair<Instantiators::iterator, bool> tmp = _instantiators.insert(make_pair(protocol, InstantiatorInfo(pSessionInstantiator)));
if (!tmp.second)
{
++tmp.first->second.cnt;
delete pSessionInstantiator;
}
}
void HTTPSessionFactory::unregisterProtocol(const std::string& protocol)
{
FastMutex::ScopedLock lock(_mutex);
Instantiators::iterator it = _instantiators.find(protocol);
if (it != _instantiators.end())
{
if (it->second.cnt == 1)
{
delete it->second.pIn;
_instantiators.erase(it);
}
else --it->second.cnt;
}
else throw NotFoundException("No HTTPSessionInstantiator registered for", protocol);
}
bool HTTPSessionFactory::supportsProtocol(const std::string& protocol)
{
FastMutex::ScopedLock lock(_mutex);
Instantiators::iterator it = _instantiators.find(protocol);
return it != _instantiators.end();
}
HTTPClientSession* HTTPSessionFactory::createClientSession(const Poco::URI& uri)
{
FastMutex::ScopedLock lock(_mutex);
if (uri.isRelative()) throw Poco::UnknownURISchemeException("Relative URIs are not supported by HTTPSessionFactory.");
Instantiators::iterator it = _instantiators.find(uri.getScheme());
if (it != _instantiators.end())
{
it->second.pIn->setProxy(_proxyHost, _proxyPort);
it->second.pIn->setProxyCredentials(_proxyUsername, _proxyPassword);
return it->second.pIn->createClientSession(uri);
}
else throw Poco::UnknownURISchemeException(uri.getScheme());
}
void HTTPSessionFactory::setProxy(const std::string& host, Poco::UInt16 port)
{
FastMutex::ScopedLock lock(_mutex);
_proxyHost = host;
_proxyPort = port;
}
void HTTPSessionFactory::setProxyCredentials(const std::string& username, const std::string& password)
{
FastMutex::ScopedLock lock(_mutex);
_proxyUsername = username;
_proxyPassword = password;
}
namespace
{
static SingletonHolder<HTTPSessionFactory> singleton;
}
HTTPSessionFactory& HTTPSessionFactory::defaultFactory()
{
return *singleton.get();
}
HTTPSessionFactory::InstantiatorInfo::InstantiatorInfo(HTTPSessionInstantiator* pInst): pIn(pInst), cnt(1)
{
poco_check_ptr (pIn);
}
} } // namespace Poco::Net
+77
View File
@@ -0,0 +1,77 @@
//
// HTTPSessionInstantiator.cpp
//
// Library: Net
// Package: HTTPClient
// Module: HTTPSessionInstantiator
//
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/HTTPSessionInstantiator.h"
#include "Poco/Net/HTTPSessionFactory.h"
#include "Poco/Net/HTTPClientSession.h"
using Poco::URI;
namespace Poco {
namespace Net {
HTTPSessionInstantiator::HTTPSessionInstantiator():
_proxyPort(0)
{
}
HTTPSessionInstantiator::~HTTPSessionInstantiator()
{
}
HTTPClientSession* HTTPSessionInstantiator::createClientSession(const Poco::URI& uri)
{
poco_assert (uri.getScheme() == "http");
HTTPClientSession* pSession = new HTTPClientSession(uri.getHost(), uri.getPort());
if (!proxyHost().empty())
{
pSession->setProxy(proxyHost(), proxyPort());
pSession->setProxyCredentials(proxyUsername(), proxyPassword());
}
return pSession;
}
void HTTPSessionInstantiator::registerInstantiator()
{
HTTPSessionFactory::defaultFactory().registerProtocol("http", new HTTPSessionInstantiator);
}
void HTTPSessionInstantiator::unregisterInstantiator()
{
HTTPSessionFactory::defaultFactory().unregisterProtocol("http");
}
void HTTPSessionInstantiator::setProxy(const std::string& host, Poco::UInt16 port)
{
_proxyHost = host;
_proxyPort = port;
}
void HTTPSessionInstantiator::setProxyCredentials(const std::string& username, const std::string& password)
{
_proxyUsername = username;
_proxyPassword = password;
}
} } // namespace Poco::Net
+172
View File
@@ -0,0 +1,172 @@
//
// HTTPStream.cpp
//
// Library: Net
// Package: HTTP
// Module: HTTPStream
//
// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/HTTPStream.h"
#include "Poco/Net/HTTPSession.h"
namespace Poco {
namespace Net {
//
// HTTPStreamBuf
//
HTTPStreamBuf::HTTPStreamBuf(HTTPSession& session, openmode mode):
HTTPBasicStreamBuf(HTTPBufferAllocator::BUFFER_SIZE, mode),
_session(session),
_mode(mode)
{
}
HTTPStreamBuf::~HTTPStreamBuf()
{
}
void HTTPStreamBuf::close()
{
if (_mode & std::ios::out)
{
sync();
_session.socket().shutdownSend();
}
}
int HTTPStreamBuf::readFromDevice(char* buffer, std::streamsize length)
{
return _session.read(buffer, length);
}
int HTTPStreamBuf::writeToDevice(const char* buffer, std::streamsize length)
{
return _session.write(buffer, length);
}
//
// HTTPIOS
//
HTTPIOS::HTTPIOS(HTTPSession& session, HTTPStreamBuf::openmode mode):
_buf(session, mode)
{
poco_ios_init(&_buf);
}
HTTPIOS::~HTTPIOS()
{
try
{
_buf.close();
}
catch (...)
{
}
}
HTTPStreamBuf* HTTPIOS::rdbuf()
{
return &_buf;
}
//
// HTTPInputStream
//
Poco::MemoryPool HTTPInputStream::_pool(sizeof(HTTPInputStream));
HTTPInputStream::HTTPInputStream(HTTPSession& session):
HTTPIOS(session, std::ios::in),
std::istream(&_buf)
{
}
HTTPInputStream::~HTTPInputStream()
{
}
void* HTTPInputStream::operator new(std::size_t size)
{
return _pool.get();
}
void HTTPInputStream::operator delete(void* ptr)
{
try
{
_pool.release(ptr);
}
catch (...)
{
poco_unexpected();
}
}
//
// HTTPOutputStream
//
Poco::MemoryPool HTTPOutputStream::_pool(sizeof(HTTPOutputStream));
HTTPOutputStream::HTTPOutputStream(HTTPSession& session):
HTTPIOS(session, std::ios::out),
std::ostream(&_buf)
{
}
HTTPOutputStream::~HTTPOutputStream()
{
}
void* HTTPOutputStream::operator new(std::size_t size)
{
return _pool.get();
}
void HTTPOutputStream::operator delete(void* ptr)
{
try
{
_pool.release(ptr);
}
catch (...)
{
poco_unexpected();
}
}
} } // namespace Poco::Net
+187
View File
@@ -0,0 +1,187 @@
//
// HTTPStreamFactory.cpp
//
// Library: Net
// Package: HTTP
// Module: HTTPStreamFactory
//
// Copyright (c) 2005-2012, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/HTTPStreamFactory.h"
#include "Poco/Net/HTTPClientSession.h"
#include "Poco/Net/HTTPIOStream.h"
#include "Poco/Net/HTTPRequest.h"
#include "Poco/Net/HTTPResponse.h"
#include "Poco/Net/HTTPCredentials.h"
#include "Poco/Net/NetException.h"
#include "Poco/URI.h"
#include "Poco/URIStreamOpener.h"
#include "Poco/UnbufferedStreamBuf.h"
#include "Poco/NullStream.h"
#include "Poco/StreamCopier.h"
#include "Poco/Format.h"
#include "Poco/Version.h"
using Poco::URIStreamFactory;
using Poco::URI;
using Poco::URIStreamOpener;
using Poco::UnbufferedStreamBuf;
namespace Poco {
namespace Net {
HTTPStreamFactory::HTTPStreamFactory():
_proxyPort(HTTPSession::HTTP_PORT)
{
}
HTTPStreamFactory::HTTPStreamFactory(const std::string& proxyHost, Poco::UInt16 proxyPort):
_proxyHost(proxyHost),
_proxyPort(proxyPort)
{
}
HTTPStreamFactory::HTTPStreamFactory(const std::string& proxyHost, Poco::UInt16 proxyPort, const std::string& proxyUsername, const std::string& proxyPassword):
_proxyHost(proxyHost),
_proxyPort(proxyPort),
_proxyUsername(proxyUsername),
_proxyPassword(proxyPassword)
{
}
HTTPStreamFactory::~HTTPStreamFactory()
{
}
std::istream* HTTPStreamFactory::open(const URI& uri)
{
poco_assert (uri.getScheme() == "http");
URI resolvedURI(uri);
URI proxyUri;
HTTPClientSession* pSession = 0;
HTTPResponse res;
bool retry = false;
bool authorize = false;
std::string username;
std::string password;
try
{
do
{
if (!pSession)
{
pSession = new HTTPClientSession(resolvedURI.getHost(), resolvedURI.getPort());
if (proxyUri.empty())
{
if (!_proxyHost.empty())
{
pSession->setProxy(_proxyHost, _proxyPort);
pSession->setProxyCredentials(_proxyUsername, _proxyPassword);
}
}
else
{
pSession->setProxy(proxyUri.getHost(), proxyUri.getPort());
if (!_proxyUsername.empty())
{
pSession->setProxyCredentials(_proxyUsername, _proxyPassword);
}
}
}
std::string path = resolvedURI.getPathAndQuery();
if (path.empty()) path = "/";
HTTPRequest req(HTTPRequest::HTTP_GET, path, HTTPMessage::HTTP_1_1);
if (authorize)
{
HTTPCredentials::extractCredentials(uri, username, password);
HTTPCredentials cred(username, password);
cred.authenticate(req, res);
}
req.set("User-Agent", Poco::format("poco/%d.%d.%d",
(POCO_VERSION >> 24) & 0xFF,
(POCO_VERSION >> 16) & 0xFF,
(POCO_VERSION >> 8) & 0xFF));
req.set("Accept", "*/*");
pSession->sendRequest(req);
std::istream& rs = pSession->receiveResponse(res);
bool moved = (res.getStatus() == HTTPResponse::HTTP_MOVED_PERMANENTLY ||
res.getStatus() == HTTPResponse::HTTP_FOUND ||
res.getStatus() == HTTPResponse::HTTP_SEE_OTHER ||
res.getStatus() == HTTPResponse::HTTP_TEMPORARY_REDIRECT);
if (moved)
{
resolvedURI.resolve(res.get("Location"));
if (!username.empty())
{
resolvedURI.setUserInfo(username + ":" + password);
}
throw URIRedirection(resolvedURI.toString());
}
else if (res.getStatus() == HTTPResponse::HTTP_OK)
{
return new HTTPResponseStream(rs, pSession);
}
else if (res.getStatus() == HTTPResponse::HTTP_USE_PROXY && !retry)
{
// The requested resource MUST be accessed through the proxy
// given by the Location field. The Location field gives the
// URI of the proxy. The recipient is expected to repeat this
// single request via the proxy. 305 responses MUST only be generated by origin servers.
// only use for one single request!
proxyUri.resolve(res.get("Location"));
delete pSession;
pSession = 0;
retry = true; // only allow useproxy once
}
else if (res.getStatus() == HTTPResponse::HTTP_UNAUTHORIZED && !authorize)
{
authorize = true;
retry = true;
Poco::NullOutputStream null;
Poco::StreamCopier::copyStream(rs, null);
}
else throw HTTPException(res.getReason(), uri.toString());
}
while (retry);
throw HTTPException("Too many redirects", uri.toString());
}
catch (...)
{
delete pSession;
throw;
}
}
void HTTPStreamFactory::registerFactory()
{
URIStreamOpener::defaultOpener().registerStreamFactory("http", new HTTPStreamFactory);
}
void HTTPStreamFactory::unregisterFactory()
{
URIStreamOpener::defaultOpener().unregisterStreamFactory("http");
}
} } // namespace Poco::Net
+135
View File
@@ -0,0 +1,135 @@
//
// HostEntry.cpp
//
// Library: Net
// Package: NetCore
// Module: HostEntry
//
// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/HostEntry.h"
#include "Poco/Exception.h"
#include <algorithm>
namespace Poco {
namespace Net {
HostEntry::HostEntry()
{
}
HostEntry::HostEntry(struct hostent* entry)
{
poco_check_ptr (entry);
_name = entry->h_name;
char** alias = entry->h_aliases;
if (alias)
{
while (*alias)
{
_aliases.push_back(std::string(*alias));
++alias;
}
}
char** address = entry->h_addr_list;
if (address)
{
while (*address)
{
_addresses.push_back(IPAddress(*address, entry->h_length));
++address;
}
}
}
#if defined(POCO_HAVE_IPv6) || defined(POCO_HAVE_ADDRINFO)
HostEntry::HostEntry(struct addrinfo* ainfo)
{
poco_check_ptr (ainfo);
for (struct addrinfo* ai = ainfo; ai; ai = ai->ai_next)
{
if (ai->ai_canonname)
{
_name.assign(ai->ai_canonname);
}
if (ai->ai_addrlen && ai->ai_addr)
{
switch (ai->ai_addr->sa_family)
{
case AF_INET:
_addresses.push_back(IPAddress(&reinterpret_cast<struct sockaddr_in*>(ai->ai_addr)->sin_addr, sizeof(in_addr)));
break;
#if defined(POCO_HAVE_IPv6)
case AF_INET6:
_addresses.push_back(IPAddress(&reinterpret_cast<struct sockaddr_in6*>(ai->ai_addr)->sin6_addr, sizeof(in6_addr), reinterpret_cast<struct sockaddr_in6*>(ai->ai_addr)->sin6_scope_id));
break;
#endif
}
}
}
}
#endif // POCO_HAVE_IPv6
#if defined(POCO_VXWORKS)
HostEntry::HostEntry(const std::string& name, const IPAddress& addr):
_name(name)
{
_addresses.push_back(addr);
}
#endif // POCO_VXWORKS
HostEntry::HostEntry(const HostEntry& entry):
_name(entry._name),
_aliases(entry._aliases),
_addresses(entry._addresses)
{
}
HostEntry& HostEntry::operator = (const HostEntry& entry)
{
if (&entry != this)
{
_name = entry._name;
_aliases = entry._aliases;
_addresses = entry._addresses;
}
return *this;
}
void HostEntry::swap(HostEntry& hostEntry)
{
std::swap(_name, hostEntry._name);
std::swap(_aliases, hostEntry._aliases);
std::swap(_addresses, hostEntry._addresses);
}
HostEntry::~HostEntry()
{
}
} } // namespace Poco::Net
+151
View File
@@ -0,0 +1,151 @@
//
// ICMPClient.cpp
//
// Library: Net
// Package: ICMP
// Module: ICMPClient
//
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/SocketAddress.h"
#include "Poco/Net/ICMPClient.h"
#include "Poco/Net/NetException.h"
#include "Poco/Channel.h"
#include "Poco/Message.h"
#include "Poco/Format.h"
#include <sstream>
using Poco::Channel;
using Poco::Message;
using Poco::InvalidArgumentException;
using Poco::NotImplementedException;
using Poco::TimeoutException;
using Poco::Exception;
namespace Poco {
namespace Net {
ICMPClient::ICMPClient(SocketAddress::Family family, int dataSize, int ttl, int timeout):
_family(family),
_dataSize(dataSize),
_ttl(ttl),
_timeout(timeout)
{
}
ICMPClient::~ICMPClient()
{
}
int ICMPClient::ping(const std::string& address, int repeat) const
{
if (repeat <= 0) return 0;
SocketAddress addr(address, 0);
return ping(addr, repeat);
}
int ICMPClient::ping(SocketAddress& address, int repeat) const
{
if (repeat <= 0) return 0;
ICMPSocket icmpSocket(_family, _dataSize, _ttl, _timeout);
ICMPEventArgs eventArgs(address, repeat, icmpSocket.dataSize(), icmpSocket.ttl());
pingBegin.notify(this, eventArgs);
for (int i = 0; i < repeat; ++i)
{
try
{
int sent = icmpSocket.sendTo(address);
if (icmpSocket.packetSize() == sent)
{
SocketAddress requestAddress(address);
++eventArgs;
int t = icmpSocket.receiveFrom(address);
poco_assert (address.host() == requestAddress.host());
eventArgs.setReplyTime(i, t);
pingReply.notify(this, eventArgs);
}
else
throw ICMPException(Poco::format("Error sending ICMP packet "
"(sent=%d, expected=%d)", sent, icmpSocket.packetSize()));
}
catch (TimeoutException&)
{
std::ostringstream os;
os << address.host().toString() << ": Request timed out.";
eventArgs.setError(i, os.str());
pingError.notify(this, eventArgs);
continue;
}
catch (ICMPException& ex)
{
std::ostringstream os;
os << address.host().toString() << ": " << ex.displayText();
eventArgs.setError(i, os.str());
pingError.notify(this, eventArgs);
continue;
}
catch (Exception& ex)
{
eventArgs.setError(i, ex.displayText());
pingError.notify(this, eventArgs);
continue;
}
}
pingEnd.notify(this, eventArgs);
return eventArgs.received();
}
int ICMPClient::pingIPv4(const std::string& address, int repeat,
int dataSize, int ttl, int timeout)
{
if (repeat <= 0) return 0;
SocketAddress a(address, 0);
return ping(a, IPAddress::IPv4, repeat, dataSize, ttl, timeout);
}
int ICMPClient::ping(SocketAddress& address,
IPAddress::Family family, int repeat,
int dataSize, int ttl, int timeout)
{
if (repeat <= 0) return 0;
ICMPSocket icmpSocket(family, dataSize, ttl, timeout);
int received = 0;
for (int i = 0; i < repeat; ++i)
{
try
{
SocketAddress requestAddress(address);
if (icmpSocket.sendTo(address) == icmpSocket.packetSize())
{
icmpSocket.receiveFrom(address);
poco_assert (address.host() == requestAddress.host());
++received;
}
}
catch (Exception&) { }
}
return received;
}
} } // namespace Poco::Net
+168
View File
@@ -0,0 +1,168 @@
//
// ICMPEventArgs.cpp
//
// Library: Net
// Package: ICMP
// Module: ICMPEventArgs
//
// Implementation of ICMPEventArgs
//
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/ICMPEventArgs.h"
#include "Poco/Net/SocketAddress.h"
#include "Poco/Net/DNS.h"
#include "Poco/Exception.h"
#include "Poco/Net/NetException.h"
#include <numeric>
using Poco::IOException;
using Poco::InvalidArgumentException;
namespace Poco {
namespace Net {
ICMPEventArgs::ICMPEventArgs(const SocketAddress& address, int repetitions, int dataSize, int ttl):
_address(address),
_sent(0),
_dataSize(dataSize),
_ttl(ttl),
_rtt(repetitions, 0),
_errors(repetitions)
{
}
ICMPEventArgs::~ICMPEventArgs()
{
}
std::string ICMPEventArgs::hostName() const
{
try
{
return DNS::resolve(_address.host().toString()).name();
}
catch (HostNotFoundException&)
{
}
catch (NoAddressFoundException&)
{
}
catch (DNSException&)
{
}
catch (IOException&)
{
}
return _address.host().toString();
}
std::string ICMPEventArgs::hostAddress() const
{
return _address.host().toString();
}
void ICMPEventArgs::setRepetitions(int repetitions)
{
_rtt.clear();
_rtt.resize(repetitions, 0);
_errors.assign(repetitions, "");
}
ICMPEventArgs& ICMPEventArgs::operator ++ ()
{
++_sent;
return *this;
}
ICMPEventArgs ICMPEventArgs::operator ++ (int)
{
ICMPEventArgs prev(*this);
operator ++ ();
return prev;
}
int ICMPEventArgs::received() const
{
int received = 0;
for (int i = 0; i < _rtt.size(); ++i)
{
if (_rtt[i]) ++received;
}
return received;
}
void ICMPEventArgs::setError(int index, const std::string& text)
{
if (index >= _errors.size())
throw InvalidArgumentException("Supplied index exceeds vector capacity.");
_errors[index] = text;
}
const std::string& ICMPEventArgs::error(int index) const
{
if (0 == _errors.size())
throw InvalidArgumentException("Supplied index exceeds vector capacity.");
if (-1 == index) index = _sent - 1;
return _errors[index];
}
void ICMPEventArgs::setReplyTime(int index, int time)
{
if (index >= _rtt.size())
throw InvalidArgumentException("Supplied index exceeds array capacity.");
if (0 == time) time = 1;
_rtt[index] = time;
}
int ICMPEventArgs::replyTime(int index) const
{
if (0 == _rtt.size())
throw InvalidArgumentException("Supplied index exceeds array capacity.");
if (-1 == index) index = _sent - 1;
return _rtt[index];
}
int ICMPEventArgs::avgRTT() const
{
if (0 == _rtt.size()) return 0;
return (int) (std::accumulate(_rtt.begin(), _rtt.end(), 0) / _rtt.size());
}
float ICMPEventArgs::percent() const
{
if (0 == _rtt.size()) return 0;
return ((float) received() / (float) _rtt.size()) * (float) 100.0;
}
} } // namespace Poco::Net
+110
View File
@@ -0,0 +1,110 @@
//
// ICMPPacket.cpp
//
// Library: Net
// Package: ICMP
// Module: ICMPPacket
//
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/ICMPPacket.h"
#include "Poco/Net/ICMPv4PacketImpl.h"
#include "Poco/Net/NetException.h"
#include "Poco/Timestamp.h"
#include "Poco/Timespan.h"
#include "Poco/NumberFormatter.h"
#include <sstream>
using Poco::InvalidArgumentException;
using Poco::NotImplementedException;
using Poco::Timestamp;
using Poco::Timespan;
using Poco::NumberFormatter;
using Poco::UInt8;
using Poco::UInt16;
using Poco::Int32;
namespace Poco {
namespace Net {
ICMPPacket::ICMPPacket(IPAddress::Family family, int dataSize):_pImpl(0)
{
if (family == IPAddress::IPv4)
_pImpl = new ICMPv4PacketImpl(dataSize);
#if defined(POCO_HAVE_IPv6)
else if (family == IPAddress::IPv6)
throw NotImplementedException("ICMPv6 packets not implemented.");
#endif
else throw InvalidArgumentException("Invalid or unsupported address family passed to ICMPPacket");
}
ICMPPacket::~ICMPPacket()
{
delete _pImpl;
}
void ICMPPacket::setDataSize(int dataSize)
{
_pImpl->setDataSize(dataSize);
}
int ICMPPacket::getDataSize() const
{
return _pImpl->getDataSize();
}
int ICMPPacket::packetSize() const
{
return _pImpl->packetSize();
}
int ICMPPacket::maxPacketSize() const
{
return _pImpl->maxPacketSize();
}
const Poco::UInt8* ICMPPacket::packet()
{
return _pImpl->packet();
}
struct timeval ICMPPacket::time(Poco::UInt8* buffer, int length) const
{
return _pImpl->time(buffer, length);
}
bool ICMPPacket::validReplyID(Poco::UInt8* buffer, int length) const
{
return _pImpl->validReplyID(buffer, length);
}
std::string ICMPPacket::errorDescription(Poco::UInt8* buffer, int length, int& type, int& code)
{
return _pImpl->errorDescription(buffer, length, type, code);
}
std::string ICMPPacket::typeDescription(int typeId)
{
return _pImpl->typeDescription(typeId);
}
} } // namespace Poco::Net
+104
View File
@@ -0,0 +1,104 @@
//
// ICMPPacketImpl.cpp
//
// Library: Net
// Package: ICMP
// Module: ICMPPacketImpl
//
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/ICMPPacketImpl.h"
#include "Poco/Net/NetException.h"
#include "Poco/Timestamp.h"
#include "Poco/Timespan.h"
#include "Poco/NumberFormatter.h"
#include <sstream>
using Poco::InvalidArgumentException;
using Poco::Timestamp;
using Poco::Timespan;
using Poco::NumberFormatter;
using Poco::UInt8;
using Poco::UInt16;
using Poco::Int32;
namespace Poco {
namespace Net {
const UInt16 ICMPPacketImpl::MAX_PACKET_SIZE = 65535;
const UInt16 ICMPPacketImpl::MAX_PAYLOAD_SIZE = 65507;
const UInt16 ICMPPacketImpl::MAX_SEQ_VALUE = 65535;
ICMPPacketImpl::ICMPPacketImpl(int dataSize):
_seq(0),
_pPacket(new UInt8[MAX_PACKET_SIZE]),
_dataSize(dataSize)
{
if (_dataSize > MAX_PACKET_SIZE)
throw InvalidArgumentException("Packet size must be <= " + NumberFormatter::format(MAX_PACKET_SIZE));
}
ICMPPacketImpl::~ICMPPacketImpl()
{
delete [] _pPacket;
}
void ICMPPacketImpl::setDataSize(int dataSize)
{
_dataSize = dataSize;
initPacket();
}
int ICMPPacketImpl::getDataSize() const
{
return _dataSize;
}
const Poco::UInt8* ICMPPacketImpl::packet(bool init)
{
if (init) initPacket();
return _pPacket;
}
unsigned short ICMPPacketImpl::checksum(UInt16 *addr, Int32 len)
{
Int32 nleft = len;
UInt16* w = addr;
UInt16 answer;
Int32 sum = 0;
while (nleft > 1)
{
sum += *w++;
nleft -= sizeof(UInt16);
}
if (nleft == 1)
{
UInt16 u = 0;
*(UInt8*) (&u) = *(UInt8*) w;
sum += u;
}
sum = (sum >> 16) + (sum & 0xffff);
sum += (sum >> 16);
answer = ~sum;
return answer;
}
} } // namespace Poco::Net
+147
View File
@@ -0,0 +1,147 @@
//
// ICMPSocket.cpp
//
// Library: Net
// Package: ICMP
// Module: ICMPSocket
//
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/ICMPSocket.h"
#include "Poco/Net/ICMPSocketImpl.h"
#include "Poco/Exception.h"
#include "Poco/Net/NetException.h"
using Poco::InvalidArgumentException;
namespace Poco {
namespace Net {
ICMPSocket::ICMPSocket(IPAddress::Family family, int dataSize, int ttl, int timeout):
Socket(new ICMPSocketImpl(family, dataSize, ttl, timeout))
{
}
ICMPSocket::ICMPSocket(const Socket& socket):
Socket(socket)
{
if (!dynamic_cast<ICMPSocketImpl*>(impl()))
throw InvalidArgumentException("Cannot assign incompatible socket");
}
ICMPSocket::ICMPSocket(SocketImpl* pImpl):
Socket(pImpl)
{
if (!dynamic_cast<ICMPSocketImpl*>(impl()))
throw InvalidArgumentException("Cannot assign incompatible socket");
}
ICMPSocket::~ICMPSocket()
{
}
ICMPSocket& ICMPSocket::operator = (const Socket& socket)
{
if (dynamic_cast<ICMPSocketImpl*>(socket.impl()))
Socket::operator = (socket);
else
throw InvalidArgumentException("Cannot assign incompatible socket");
return *this;
}
int ICMPSocket::sendTo(const SocketAddress& address, int flags)
{
return impl()->sendTo(0, 0, address, flags);
}
int ICMPSocket::receiveFrom(SocketAddress& address, int flags)
{
return impl()->receiveFrom(0, 0, address, flags);
}
int ICMPSocket::dataSize() const
{
return static_cast<ICMPSocketImpl*>(impl())->dataSize();
}
int ICMPSocket::packetSize() const
{
return static_cast<ICMPSocketImpl*>(impl())->packetSize();
}
int ICMPSocket::ttl() const
{
return static_cast<ICMPSocketImpl*>(impl())->ttl();
}
int ICMPSocket::timeout() const
{
return static_cast<ICMPSocketImpl*>(impl())->timeout();
}
Poco::UInt16 ICMPSocket::mtu(const SocketAddress& address, Poco::UInt16 sz)
{
if (address.family() != IPAddress::IPv4) return 0;
SocketAddress returnAddress(address);
for (; sz >= 68 /*RFC791*/; --sz)
{
ICMPSocket icmpSocket(address.family(), sz);
#ifdef IP_DONTFRAGMENT
icmpSocket.setOption(IPPROTO_IP, IP_DONTFRAGMENT, 1);
#elif defined(IP_MTU_DISCOVER)
icmpSocket.setOption(IPPROTO_IP, IP_MTU_DISCOVER, IP_PMTUDISC_DO);
#elif defined(IP_DONTFRAG)
icmpSocket.setOption(IPPROTO_IP, IP_DONTFRAG, 1);
#else
throw NotImplementedException("ICMPSocket::mtu()");
#endif
try
{
icmpSocket.sendTo(address);
icmpSocket.receiveFrom(returnAddress);
poco_assert_dbg (returnAddress == address);
return sz;
}
catch (ICMPFragmentationException&)
{
// PMTU fragmentation, continue discovery
continue;
}
catch (NetException& ex)
{
// local MTU limit, continue discovery
if (ex.code() == POCO_EMSGSIZE)
continue;
}
catch (Exception&)
{
return 0;
}
}
return 0;
}
} } // namespace Poco::Net
+131
View File
@@ -0,0 +1,131 @@
//
// ICMPSocketImpl.cpp
//
// Library: Net
// Package: ICMP
// Module: ICMPSocketImpl
//
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/ICMPSocketImpl.h"
#include "Poco/Net/ICMPv4PacketImpl.h"
#include "Poco/Net/NetException.h"
#include "Poco/Format.h"
#include "Poco/Buffer.h"
using Poco::TimeoutException;
using Poco::Timespan;
using Poco::Exception;
namespace Poco {
namespace Net {
ICMPSocketImpl::ICMPSocketImpl(IPAddress::Family family, int dataSize, int ttl, int timeout):
RawSocketImpl(family, IPPROTO_ICMP),
_icmpPacket(family, dataSize),
_ttl(ttl),
_timeout(timeout)
{
setOption(IPPROTO_IP, IP_TTL, ttl);
setBlocking(true);
setReceiveTimeout(Timespan(timeout));
}
ICMPSocketImpl::~ICMPSocketImpl()
{
}
int ICMPSocketImpl::sendTo(const void*, int, const SocketAddress& address, int flags)
{
int n = SocketImpl::sendTo(_icmpPacket.packet(), _icmpPacket.packetSize(), address, flags);
return n;
}
void ICMPSocketImpl::checkFragmentation(const std::string& err, int type, int code)
{
if (type == ICMPv4PacketImpl::DESTINATION_UNREACHABLE &&
code == ICMPv4PacketImpl::FRAGMENTATION_NEEDED_AND_DF_SET)
{
throw ICMPFragmentationException(err);
}
}
int ICMPSocketImpl::receiveFrom(void*, int, SocketAddress& address, int flags)
{
int maxPacketSize = _icmpPacket.maxPacketSize();
Poco::Buffer<unsigned char> buffer(maxPacketSize);
int expected = _icmpPacket.packetSize();
int type = 0, code = 0;
try
{
Poco::Timestamp ts;
int rc;
do
{
// guard against a DoS attack
if (ts.isElapsed(_timeout)) throw TimeoutException();
buffer.clear();
SocketAddress respAddr;
rc = SocketImpl::receiveFrom(buffer.begin(), maxPacketSize, respAddr, flags);
if (rc == 0) break;
if (respAddr == address)
{
expected -= rc;
if (expected <= 0)
{
if (_icmpPacket.validReplyID(buffer.begin(), maxPacketSize)) break;
std::string err = _icmpPacket.errorDescription(buffer.begin(), maxPacketSize, type, code);
if (address.family() == IPAddress::IPv4) checkFragmentation(err, type, code);
if (!err.empty()) throw ICMPException(err);
throw ICMPException("Invalid ICMP reply");
}
}
else continue;
}
while (expected > 0 && !_icmpPacket.validReplyID(buffer.begin(), maxPacketSize));
}
catch (ICMPException&)
{
throw;
}
catch (TimeoutException&)
{
throw;
}
catch (Exception&)
{
std::string err = _icmpPacket.errorDescription(buffer.begin(), maxPacketSize, type, code);
if (address.family() == IPAddress::IPv4) checkFragmentation(err, type, code);
if (!err.empty()) throw ICMPException(err);
else throw;
}
if (expected > 0)
{
throw ICMPException(Poco::format("No response: expected %d, received: %d", _icmpPacket.packetSize(),
_icmpPacket.packetSize() - expected));
}
struct timeval then = _icmpPacket.time(buffer.begin(), maxPacketSize);
struct timeval now = _icmpPacket.time();
int elapsed = (((now.tv_sec * 1000000) + now.tv_usec) - ((then.tv_sec * 1000000) + then.tv_usec))/1000;
return elapsed;
}
} } // namespace Poco::Net
+264
View File
@@ -0,0 +1,264 @@
//
// ICMPv4PacketImpl.cpp
//
// Library: Net
// Package: ICMP
// Module: ICMPv4PacketImpl
//
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/ICMPv4PacketImpl.h"
#include "Poco/Net/NetException.h"
#include "Poco/Timestamp.h"
#include "Poco/Timespan.h"
#include "Poco/NumberFormatter.h"
#if !defined(POCO_VXWORKS)
#include "Poco/Process.h"
#endif
#include <sstream>
using Poco::InvalidArgumentException;
using Poco::Timestamp;
using Poco::Timespan;
using Poco::NumberFormatter;
using Poco::UInt8;
using Poco::UInt16;
using Poco::Int32;
namespace Poco {
namespace Net {
const UInt8 ICMPv4PacketImpl::DESTINATION_UNREACHABLE_TYPE = 3;
const Poco::UInt8 ICMPv4PacketImpl::SOURCE_QUENCH_TYPE = 4;
const Poco::UInt8 ICMPv4PacketImpl::REDIRECT_MESSAGE_TYPE = 5;
const UInt8 ICMPv4PacketImpl::TIME_EXCEEDED_TYPE = 11;
const Poco::UInt8 ICMPv4PacketImpl::PARAMETER_PROBLEM_TYPE = 12;
const std::string ICMPv4PacketImpl::MESSAGE_TYPE[] =
{
"Echo Reply",
"ICMP 1",
"ICMP 2",
"Dest Unreachable",
"Source Quench",
"Redirect",
"ICMP 6",
"ICMP 7",
"Echo",
"ICMP 9",
"ICMP 10",
"Time Exceeded",
"Parameter Problem",
"Timestamp",
"Timestamp Reply",
"Info Request",
"Info Reply",
"Unknown type"
};
const std::string ICMPv4PacketImpl::DESTINATION_UNREACHABLE_CODE[] =
{
"Net unreachable",
"Host unreachable",
"Protocol unreachable",
"Port unreachable",
"Fragmentation needed and DF set",
"Source route failed",
"Unknown code"
};
const std::string ICMPv4PacketImpl::REDIRECT_MESSAGE_CODE[] =
{
"Redirect datagrams for the network",
"Redirect datagrams for the host",
"Redirect datagrams for the type of service and network",
"Redirect datagrams for the type of service and host",
"Unknown code"
};
const std::string ICMPv4PacketImpl::TIME_EXCEEDED_CODE[] =
{
"Time to live exceeded in transit",
"Fragment reassembly time exceeded",
"Unknown code"
};
const std::string ICMPv4PacketImpl::PARAMETER_PROBLEM_CODE[] =
{
"Pointer indicates the error",
"Unknown code"
};
ICMPv4PacketImpl::ICMPv4PacketImpl(int dataSize)
: ICMPPacketImpl(dataSize),
_seq(0)
{
initPacket();
}
ICMPv4PacketImpl::~ICMPv4PacketImpl()
{
}
int ICMPv4PacketImpl::packetSize() const
{
return getDataSize() + sizeof(Header);
}
void ICMPv4PacketImpl::initPacket()
{
if (_seq >= MAX_SEQ_VALUE) resetSequence();
Header* icp = (Header*) packet(false);
icp->type = ECHO_REQUEST;
icp->code = 0;
icp->checksum = 0;
icp->seq = ++_seq;
#if defined(POCO_VXWORKS)
icp->id = 0;
#else
icp->id = static_cast<UInt16>(Poco::Process::id());
#endif
struct timeval* ptp = (struct timeval *) (icp + 1);
*ptp = time();
icp->checksum = checksum((UInt16*) icp, getDataSize() + sizeof(Header));
}
struct timeval ICMPv4PacketImpl::time(Poco::UInt8* buffer, int length) const
{
struct timeval tv;
if (0 == buffer || 0 == length)
{
Timespan value(Timestamp().epochMicroseconds());
tv.tv_sec = (long) value.totalSeconds();
tv.tv_usec = (long) value.useconds();
}
else
{
struct timeval* ptv = (struct timeval*) data(buffer, length);
if (ptv) tv = *ptv;
else throw InvalidArgumentException("Invalid packet.");
}
return tv;
}
ICMPv4PacketImpl::Header* ICMPv4PacketImpl::header(Poco::UInt8* buffer, int length) const
{
poco_check_ptr (buffer);
int offset = (buffer[0] & 0x0F) * 4;
if ((offset + sizeof(Header)) > length) return 0;
buffer += offset;
return (Header *) buffer;
}
Poco::UInt8* ICMPv4PacketImpl::data(Poco::UInt8* buffer, int length) const
{
return ((Poco::UInt8*) header(buffer, length)) + sizeof(Header);
}
bool ICMPv4PacketImpl::validReplyID(Poco::UInt8* buffer, int length) const
{
Header *icp = header(buffer, length);
#if defined(POCO_VXWORKS)
return icp && icp->id == 0;
#else
return icp && (static_cast<Poco::UInt16>(Process::id()) == icp->id);
#endif
}
std::string ICMPv4PacketImpl::errorDescription(unsigned char* buffer, int length, int& type, int& code)
{
Header *icp = header(buffer, length);
if (!icp) return "Invalid header.";
if (ECHO_REPLY == icp->type) return std::string(); // not an error
UInt8 pointer = 0;
if (PARAMETER_PROBLEM == icp->type)
{
UInt8 mask = 0x00FF;
pointer = icp->id & mask;
}
type = icp->type;
MessageType msgType = static_cast<MessageType>(type);
code = icp->code;
std::ostringstream err;
switch (msgType)
{
case DESTINATION_UNREACHABLE_TYPE:
if (code >= NET_UNREACHABLE && code < DESTINATION_UNREACHABLE_UNKNOWN)
err << DESTINATION_UNREACHABLE_CODE[code];
else
err << DESTINATION_UNREACHABLE_CODE[DESTINATION_UNREACHABLE_UNKNOWN];
break;
case SOURCE_QUENCH_TYPE:
err << "Source quench";
break;
case REDIRECT_MESSAGE_TYPE:
if (code >= REDIRECT_NETWORK && code < REDIRECT_MESSAGE_UNKNOWN)
err << REDIRECT_MESSAGE_CODE[code];
else
err << REDIRECT_MESSAGE_CODE[REDIRECT_MESSAGE_UNKNOWN];
break;
case TIME_EXCEEDED_TYPE:
if (code >= TIME_TO_LIVE || code < TIME_EXCEEDED_UNKNOWN)
err << TIME_EXCEEDED_CODE[code];
else
err << TIME_EXCEEDED_CODE[TIME_EXCEEDED_UNKNOWN];
break;
case PARAMETER_PROBLEM_TYPE:
if (POINTER_INDICATES_THE_ERROR != code)
code = PARAMETER_PROBLEM_UNKNOWN;
err << PARAMETER_PROBLEM_CODE[code] << ": error in octet #" << pointer;
break;
default:
err << "Unknown type.";
break;
}
return err.str();
}
std::string ICMPv4PacketImpl::typeDescription(int typeId)
{
poco_assert (typeId >= ECHO_REPLY && typeId < MESSAGE_TYPE_LENGTH);
return MESSAGE_TYPE[typeId];
}
} } // namespace Poco::Net
+601
View File
@@ -0,0 +1,601 @@
//
// IPAddress.cpp
//
// Library: Net
// Package: NetCore
// Module: IPAddress
//
// Copyright (c) 2005-2011, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/IPAddress.h"
#include "Poco/Net/NetException.h"
#include "Poco/RefCountedObject.h"
#include "Poco/NumberFormatter.h"
#include "Poco/BinaryReader.h"
#include "Poco/BinaryWriter.h"
#include "Poco/String.h"
#include "Poco/Types.h"
using Poco::RefCountedObject;
using Poco::NumberFormatter;
using Poco::BinaryReader;
using Poco::BinaryWriter;
using Poco::toLower;
using Poco::trim;
using Poco::UInt8;
using Poco::UInt16;
using Poco::UInt32;
using Poco::Net::Impl::IPAddressImpl;
using Poco::Net::Impl::IPv4AddressImpl;
#if defined(POCO_HAVE_IPv6)
using Poco::Net::Impl::IPv6AddressImpl;
#endif
namespace Poco {
namespace Net {
#if !defined(_MSC_VER) || defined(__STDC__)
// Go home MSVC, you're drunk...
// See http://stackoverflow.com/questions/5899857/multiple-definition-error-for-static-const-class-members
const IPAddress::Family IPAddress::IPv4;
#if defined(POCO_HAVE_IPv6)
const IPAddress::Family IPAddress::IPv6;
#endif
#endif
IPAddress::IPAddress()
{
newIPv4();
}
IPAddress::IPAddress(const IPAddress& addr)
{
if (addr.family() == IPv4)
newIPv4(addr.addr());
#if defined(POCO_HAVE_IPv6)
else
newIPv6(addr.addr(), addr.scope());
#endif
}
IPAddress::IPAddress(Family family)
{
if (family == IPv4)
newIPv4();
#if defined(POCO_HAVE_IPv6)
else if (family == IPv6)
newIPv6();
#endif
else throw Poco::InvalidArgumentException("Invalid or unsupported address family passed to IPAddress()");
}
IPAddress::IPAddress(const std::string& addr)
{
IPv4AddressImpl empty4 = IPv4AddressImpl();
if (addr.empty() || trim(addr) == "0.0.0.0")
{
newIPv4(empty4.addr());
return;
}
IPv4AddressImpl addr4(IPv4AddressImpl::parse(addr));
if (addr4 != empty4)
{
newIPv4(addr4.addr());
return;
}
#if defined(POCO_HAVE_IPv6)
IPv6AddressImpl empty6 = IPv6AddressImpl();
if (addr.empty() || trim(addr) == "::")
{
newIPv6(empty6.addr());
return;
}
IPv6AddressImpl addr6(IPv6AddressImpl::parse(addr));
if (addr6 != IPv6AddressImpl())
{
newIPv6(addr6.addr(), addr6.scope());
return;
}
#endif
throw InvalidAddressException(addr);
}
IPAddress::IPAddress(const std::string& addr, Family family)
{
if (family == IPv4)
{
IPv4AddressImpl addr4(IPv4AddressImpl::parse(addr));
newIPv4(addr4.addr());
return;
}
#if defined(POCO_HAVE_IPv6)
else if (family == IPv6)
{
IPv6AddressImpl addr6(IPv6AddressImpl::parse(addr));
newIPv6(addr6.addr(), addr6.scope());
return;
}
#endif
else throw Poco::InvalidArgumentException("Invalid or unsupported address family passed to IPAddress()");
}
IPAddress::IPAddress(const void* addr, poco_socklen_t length)
: _pImpl(0)
{
if (length == sizeof(struct in_addr))
newIPv4(addr);
#if defined(POCO_HAVE_IPv6)
else if (length == sizeof(struct in6_addr))
newIPv6(addr);
#endif
else throw Poco::InvalidArgumentException("Invalid address length passed to IPAddress()");
}
IPAddress::IPAddress(const void* addr, poco_socklen_t length, Poco::UInt32 scope)
{
if (length == sizeof(struct in_addr))
newIPv4(addr);
#if defined(POCO_HAVE_IPv6)
else if (length == sizeof(struct in6_addr))
newIPv6(addr, scope);
#endif
else throw Poco::InvalidArgumentException("Invalid address length passed to IPAddress()");
}
IPAddress::IPAddress(unsigned prefix, Family family)
{
if (family == IPv4)
{
if (prefix <= 32)
newIPv4(prefix);
else
throw Poco::InvalidArgumentException("Invalid prefix length passed to IPAddress()");
}
#if defined(POCO_HAVE_IPv6)
else if (family == IPv6)
{
if (prefix <= 128)
newIPv6(prefix);
else
throw Poco::InvalidArgumentException("Invalid prefix length passed to IPAddress()");
}
#endif
else throw Poco::InvalidArgumentException("Invalid or unsupported address family passed to IPAddress()");
}
#if defined(_WIN32)
IPAddress::IPAddress(const SOCKET_ADDRESS& socket_address)
: _pImpl(0)
{
ADDRESS_FAMILY family = socket_address.lpSockaddr->sa_family;
if (family == AF_INET)
newIPv4(&reinterpret_cast<const struct sockaddr_in*>(socket_address.lpSockaddr)->sin_addr);
#if defined(POCO_HAVE_IPv6)
else if (family == AF_INET6)
newIPv6(&reinterpret_cast<const struct sockaddr_in6*>(socket_address.lpSockaddr)->sin6_addr,
reinterpret_cast<const struct sockaddr_in6*>(socket_address.lpSockaddr)->sin6_scope_id);
#endif
else throw Poco::InvalidArgumentException("Invalid or unsupported address family passed to IPAddress()");
}
#endif
IPAddress::IPAddress(const struct sockaddr& sockaddr)
{
unsigned short family = sockaddr.sa_family;
if (family == AF_INET)
newIPv4(&reinterpret_cast<const struct sockaddr_in*>(&sockaddr)->sin_addr);
#if defined(POCO_HAVE_IPv6)
else if (family == AF_INET6)
newIPv6(&reinterpret_cast<const struct sockaddr_in6*>(&sockaddr)->sin6_addr,
reinterpret_cast<const struct sockaddr_in6*>(&sockaddr)->sin6_scope_id);
#endif
else throw Poco::InvalidArgumentException("Invalid or unsupported address family passed to IPAddress()");
}
IPAddress::~IPAddress()
{
}
IPAddress& IPAddress::operator = (const IPAddress& addr)
{
if (&addr != this)
{
if (addr.family() == IPAddress::IPv4)
newIPv4(addr.addr());
#if defined(POCO_HAVE_IPv6)
else if (addr.family() == IPAddress::IPv6)
newIPv6(addr.addr(), addr.scope());
#endif
else
throw Poco::InvalidArgumentException("Invalid or unsupported address family");
}
return *this;
}
IPAddress::Family IPAddress::family() const
{
return pImpl()->family();
}
Poco::UInt32 IPAddress::scope() const
{
return pImpl()->scope();
}
std::string IPAddress::toString() const
{
return pImpl()->toString();
}
bool IPAddress::isWildcard() const
{
return pImpl()->isWildcard();
}
bool IPAddress::isBroadcast() const
{
return pImpl()->isBroadcast();
}
bool IPAddress::isLoopback() const
{
return pImpl()->isLoopback();
}
bool IPAddress::isMulticast() const
{
return pImpl()->isMulticast();
}
bool IPAddress::isUnicast() const
{
return !isWildcard() && !isBroadcast() && !isMulticast();
}
bool IPAddress::isLinkLocal() const
{
return pImpl()->isLinkLocal();
}
bool IPAddress::isSiteLocal() const
{
return pImpl()->isSiteLocal();
}
bool IPAddress::isIPv4Compatible() const
{
return pImpl()->isIPv4Compatible();
}
bool IPAddress::isIPv4Mapped() const
{
return pImpl()->isIPv4Mapped();
}
bool IPAddress::isWellKnownMC() const
{
return pImpl()->isWellKnownMC();
}
bool IPAddress::isNodeLocalMC() const
{
return pImpl()->isNodeLocalMC();
}
bool IPAddress::isLinkLocalMC() const
{
return pImpl()->isLinkLocalMC();
}
bool IPAddress::isSiteLocalMC() const
{
return pImpl()->isSiteLocalMC();
}
bool IPAddress::isOrgLocalMC() const
{
return pImpl()->isOrgLocalMC();
}
bool IPAddress::isGlobalMC() const
{
return pImpl()->isGlobalMC();
}
bool IPAddress::operator == (const IPAddress& a) const
{
poco_socklen_t l1 = length();
poco_socklen_t l2 = a.length();
if (l1 == l2)
{
#if defined(POCO_HAVE_IPv6)
if ( scope() != a.scope() )
return false;
#endif
return std::memcmp(addr(), a.addr(), l1) == 0;
}
else return false;
}
bool IPAddress::operator != (const IPAddress& a) const
{
return !(*this == a);
}
bool IPAddress::operator < (const IPAddress& a) const
{
poco_socklen_t l1 = length();
poco_socklen_t l2 = a.length();
if (l1 == l2)
{
#if defined(POCO_HAVE_IPv6)
if ( scope() != a.scope() )
return scope() < a.scope();
#endif
return std::memcmp(addr(), a.addr(), l1) < 0;
}
else return l1 < l2;
}
bool IPAddress::operator <= (const IPAddress& a) const
{
return !(a < *this);
}
bool IPAddress::operator > (const IPAddress& a) const
{
return a < *this;
}
bool IPAddress::operator >= (const IPAddress& a) const
{
return !(*this < a);
}
IPAddress IPAddress::operator & (const IPAddress& other) const
{
if (family() == other.family())
{
if (family() == IPv4)
{
IPv4AddressImpl t(pImpl()->addr());
IPv4AddressImpl o(other.pImpl()->addr());
return IPAddress((t & o).addr(), sizeof(struct in_addr));
}
#if defined(POCO_HAVE_IPv6)
else if (family() == IPv6)
{
const IPv6AddressImpl t(pImpl()->addr(), pImpl()->scope());
const IPv6AddressImpl o(other.pImpl()->addr(), other.pImpl()->scope());
const IPv6AddressImpl r = t & o;
return IPAddress(r.addr(), sizeof(struct in6_addr), r.scope());
}
#endif
else throw Poco::InvalidArgumentException("Invalid or unsupported address family passed to IPAddress()");
}
else throw Poco::InvalidArgumentException("Invalid or unsupported address family passed to IPAddress()");
}
IPAddress IPAddress::operator | (const IPAddress& other) const
{
if (family() == other.family())
{
if (family() == IPv4)
{
IPv4AddressImpl t(pImpl()->addr());
IPv4AddressImpl o(other.pImpl()->addr());
return IPAddress((t | o).addr(), sizeof(struct in_addr));
}
#if defined(POCO_HAVE_IPv6)
else if (family() == IPv6)
{
const IPv6AddressImpl t(pImpl()->addr(), pImpl()->scope());
const IPv6AddressImpl o(other.pImpl()->addr(), other.pImpl()->scope());
const IPv6AddressImpl r = t | o;
return IPAddress(r.addr(), sizeof(struct in6_addr), r.scope());
}
#endif
else throw Poco::InvalidArgumentException("Invalid or unsupported address family passed to IPAddress()");
}
else throw Poco::InvalidArgumentException("Invalid or unsupported address family passed to IPAddress()");
}
IPAddress IPAddress::operator ^ (const IPAddress& other) const
{
if (family() == other.family())
{
if (family() == IPv4)
{
IPv4AddressImpl t(pImpl()->addr());
IPv4AddressImpl o(other.pImpl()->addr());
return IPAddress((t ^ o).addr(), sizeof(struct in_addr));
}
#if defined(POCO_HAVE_IPv6)
else if (family() == IPv6)
{
const IPv6AddressImpl t(pImpl()->addr(), pImpl()->scope());
const IPv6AddressImpl o(other.pImpl()->addr(), other.pImpl()->scope());
const IPv6AddressImpl r = t ^ o;
return IPAddress(r.addr(), sizeof(struct in6_addr), r.scope());
}
#endif
else throw Poco::InvalidArgumentException("Invalid or unsupported address family passed to IPAddress()");
}
else throw Poco::InvalidArgumentException("Invalid or unsupported address family passed to IPAddress()");
}
IPAddress IPAddress::operator ~ () const
{
if (family() == IPv4)
{
IPv4AddressImpl self(this->pImpl()->addr());
return IPAddress((~self).addr(), sizeof(struct in_addr));
}
#if defined(POCO_HAVE_IPv6)
else if (family() == IPv6)
{
const IPv6AddressImpl self(pImpl()->addr(), pImpl()->scope());
const IPv6AddressImpl r = ~self;
return IPAddress(r.addr(), sizeof(struct in6_addr), r.scope());
}
#endif
else throw Poco::InvalidArgumentException("Invalid or unsupported address family passed to IPAddress()");
}
poco_socklen_t IPAddress::length() const
{
return pImpl()->length();
}
const void* IPAddress::addr() const
{
return pImpl()->addr();
}
int IPAddress::af() const
{
return pImpl()->af();
}
unsigned IPAddress::prefixLength() const
{
return pImpl()->prefixLength();
}
IPAddress IPAddress::parse(const std::string& addr)
{
return IPAddress(addr);
}
bool IPAddress::tryParse(const std::string& addr, IPAddress& result)
{
IPv4AddressImpl impl4(IPv4AddressImpl::parse(addr));
if (impl4 != IPv4AddressImpl() || trim(addr) == "0.0.0.0")
{
result.newIPv4(impl4.addr());
return true;
}
#if defined(POCO_HAVE_IPv6)
IPv6AddressImpl impl6(IPv6AddressImpl::parse(addr));
if (impl6 != IPv6AddressImpl())
{
result.newIPv6(impl6.addr(), impl6.scope());
return true;
}
#endif
return false;
}
void IPAddress::mask(const IPAddress& mask)
{
IPAddress null;
pImpl()->mask(mask.pImpl(), null.pImpl());
}
void IPAddress::mask(const IPAddress& mask, const IPAddress& set)
{
pImpl()->mask(mask.pImpl(), set.pImpl());
}
IPAddress IPAddress::wildcard(Family family)
{
return IPAddress(family);
}
IPAddress IPAddress::broadcast()
{
struct in_addr ia;
ia.s_addr = INADDR_NONE;
return IPAddress(&ia, sizeof(ia));
}
} } // namespace Poco::Net
Poco::BinaryWriter& operator << (Poco::BinaryWriter& writer, const Poco::Net::IPAddress& value)
{
writer << static_cast<Poco::UInt8>(value.length());
writer.writeRaw(reinterpret_cast<const char*>(value.addr()), value.length());
return writer;
}
Poco::BinaryReader& operator >> (Poco::BinaryReader& reader, Poco::Net::IPAddress& value)
{
char buf[Poco::Net::IPAddress::MAX_ADDRESS_LENGTH];
Poco::UInt8 length;
reader >> length;
reader.readRaw(buf, length);
value = Poco::Net::IPAddress(buf, length);
return reader;
}
std::ostream& operator << (std::ostream& ostr, const Poco::Net::IPAddress& addr)
{
ostr << addr.toString();
return ostr;
}
+813
View File
@@ -0,0 +1,813 @@
//
// IPAddress.cpp
//
// Library: Net
// Package: NetCore
// Module: IPAddress
//
// Copyright (c) 2005-2011, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/IPAddressImpl.h"
#include "Poco/Net/NetException.h"
#include "Poco/RefCountedObject.h"
#include "Poco/NumberFormatter.h"
#include "Poco/ByteOrder.h"
#include "Poco/String.h"
#include "Poco/Types.h"
using Poco::RefCountedObject;
using Poco::NumberFormatter;
using Poco::toLower;
using Poco::UInt8;
using Poco::UInt16;
using Poco::UInt32;
namespace {
template <typename T>
unsigned maskBits(T val, unsigned size)
/// Returns the length of the mask (number of bits set in val).
/// The val should be either all zeros or two contiguos areas of 1s and 0s.
/// The algorithm ignores invalid non-contiguous series of 1s and treats val
/// as if all bits between MSb and last non-zero bit are set to 1.
{
unsigned count = 0;
if (val)
{
val = (val ^ (val - 1)) >> 1;
for (count = 0; val; ++count) val >>= 1;
}
else count = size;
return size - count;
}
} // namespace
namespace Poco {
namespace Net {
namespace Impl {
//
// IPAddressImpl
//
IPAddressImpl::IPAddressImpl()
{
}
IPAddressImpl::~IPAddressImpl()
{
}
//
// IPv4AddressImpl
//
IPv4AddressImpl::IPv4AddressImpl()
{
std::memset(&_addr, 0, sizeof(_addr));
}
IPv4AddressImpl::IPv4AddressImpl(const void* addr)
{
std::memcpy(&_addr, addr, sizeof(_addr));
}
IPv4AddressImpl::IPv4AddressImpl(unsigned prefix)
{
UInt32 addr = (prefix == 32) ? 0xffffffff : ~(0xffffffff >> prefix);
_addr.s_addr = ByteOrder::toNetwork(addr);
}
IPv4AddressImpl::IPv4AddressImpl(const IPv4AddressImpl& addr)
{
std::memcpy(&_addr, &addr._addr, sizeof(_addr));
}
IPv4AddressImpl& IPv4AddressImpl::operator = (const IPv4AddressImpl& addr)
{
if (this == &addr)
return *this;
std::memcpy(&_addr, &addr._addr, sizeof(_addr));
return *this;
}
std::string IPv4AddressImpl::toString() const
{
const UInt8* bytes = reinterpret_cast<const UInt8*>(&_addr);
std::string result;
result.reserve(16);
NumberFormatter::append(result, bytes[0]);
result.append(".");
NumberFormatter::append(result, bytes[1]);
result.append(".");
NumberFormatter::append(result, bytes[2]);
result.append(".");
NumberFormatter::append(result, bytes[3]);
return result;
}
poco_socklen_t IPv4AddressImpl::length() const
{
return sizeof(_addr);
}
const void* IPv4AddressImpl::addr() const
{
return &_addr;
}
IPAddressImpl::Family IPv4AddressImpl::family() const
{
return AddressFamily::IPv4;
}
int IPv4AddressImpl::af() const
{
return AF_INET;
}
unsigned IPv4AddressImpl::prefixLength() const
{
return maskBits(ntohl(_addr.s_addr), 32);
}
Poco::UInt32 IPv4AddressImpl::scope() const
{
return 0;
}
bool IPv4AddressImpl::isWildcard() const
{
return _addr.s_addr == INADDR_ANY;
}
bool IPv4AddressImpl::isBroadcast() const
{
return _addr.s_addr == INADDR_NONE;
}
bool IPv4AddressImpl::isLoopback() const
{
return (ntohl(_addr.s_addr) & 0xFF000000) == 0x7F000000; // 127.0.0.1 to 127.255.255.255
}
bool IPv4AddressImpl::isMulticast() const
{
return (ntohl(_addr.s_addr) & 0xF0000000) == 0xE0000000; // 224.0.0.0/24 to 239.0.0.0/24
}
bool IPv4AddressImpl::isLinkLocal() const
{
return (ntohl(_addr.s_addr) & 0xFFFF0000) == 0xA9FE0000; // 169.254.0.0/16
}
bool IPv4AddressImpl::isSiteLocal() const
{
UInt32 addr = ntohl(_addr.s_addr);
return (addr & 0xFF000000) == 0x0A000000 || // 10.0.0.0/24
(addr & 0xFFFF0000) == 0xC0A80000 || // 192.68.0.0/16
(addr >= 0xAC100000 && addr <= 0xAC1FFFFF); // 172.16.0.0 to 172.31.255.255
}
bool IPv4AddressImpl::isIPv4Compatible() const
{
return true;
}
bool IPv4AddressImpl::isIPv4Mapped() const
{
return true;
}
bool IPv4AddressImpl::isWellKnownMC() const
{
return (ntohl(_addr.s_addr) & 0xFFFFFF00) == 0xE0000000; // 224.0.0.0/8
}
bool IPv4AddressImpl::isNodeLocalMC() const
{
return false;
}
bool IPv4AddressImpl::isLinkLocalMC() const
{
return (ntohl(_addr.s_addr) & 0xFF000000) == 0xE0000000; // 244.0.0.0/24
}
bool IPv4AddressImpl::isSiteLocalMC() const
{
return (ntohl(_addr.s_addr) & 0xFFFF0000) == 0xEFFF0000; // 239.255.0.0/16
}
bool IPv4AddressImpl::isOrgLocalMC() const
{
return (ntohl(_addr.s_addr) & 0xFFFF0000) == 0xEFC00000; // 239.192.0.0/16
}
bool IPv4AddressImpl::isGlobalMC() const
{
UInt32 addr = ntohl(_addr.s_addr);
return addr >= 0xE0000100 && addr <= 0xEE000000; // 224.0.1.0 to 238.255.255.255
}
IPv4AddressImpl IPv4AddressImpl::parse(const std::string& addr)
{
if (addr.empty()) return IPv4AddressImpl();
#if defined(_WIN32)
struct in_addr ia;
ia.s_addr = inet_addr(addr.c_str());
if (ia.s_addr == INADDR_NONE && addr != "255.255.255.255")
return IPv4AddressImpl();
else
return IPv4AddressImpl(&ia);
#else
#if __GNUC__ < 3 || defined(POCO_VXWORKS)
struct in_addr ia;
ia.s_addr = inet_addr(const_cast<char*>(addr.c_str()));
if (ia.s_addr == INADDR_NONE && addr != "255.255.255.255")
return IPv4AddressImpl();
else
return IPv4AddressImpl(&ia);
#else
struct in_addr ia;
if (inet_aton(addr.c_str(), &ia))
return IPv4AddressImpl(&ia);
else
return IPv4AddressImpl();
#endif
#endif
}
void IPv4AddressImpl::mask(const IPAddressImpl* pMask, const IPAddressImpl* pSet)
{
poco_assert (pMask->af() == AF_INET && pSet->af() == AF_INET);
_addr.s_addr &= static_cast<const IPv4AddressImpl*>(pMask)->_addr.s_addr;
_addr.s_addr |= static_cast<const IPv4AddressImpl*>(pSet)->_addr.s_addr & ~static_cast<const IPv4AddressImpl*>(pMask)->_addr.s_addr;
}
IPAddressImpl* IPv4AddressImpl::clone() const
{
return new IPv4AddressImpl(&_addr);
}
IPv4AddressImpl IPv4AddressImpl::operator & (const IPv4AddressImpl& addr) const
{
IPv4AddressImpl result(&_addr);
result._addr.s_addr &= addr._addr.s_addr;
return result;
}
IPv4AddressImpl IPv4AddressImpl::operator | (const IPv4AddressImpl& addr) const
{
IPv4AddressImpl result(&_addr);
result._addr.s_addr |= addr._addr.s_addr;
return result;
}
IPv4AddressImpl IPv4AddressImpl::operator ^ (const IPv4AddressImpl& addr) const
{
IPv4AddressImpl result(&_addr);
result._addr.s_addr ^= addr._addr.s_addr;
return result;
}
IPv4AddressImpl IPv4AddressImpl::operator ~ () const
{
IPv4AddressImpl result(&_addr);
result._addr.s_addr ^= 0xffffffff;
return result;
}
bool IPv4AddressImpl::operator == (const IPv4AddressImpl& addr) const
{
return 0 == std::memcmp(&addr._addr, &_addr, sizeof(_addr));
}
bool IPv4AddressImpl::operator != (const IPv4AddressImpl& addr) const
{
return !(*this == addr);
}
#if defined(POCO_HAVE_IPv6)
//
// IPv6AddressImpl
//
IPv6AddressImpl::IPv6AddressImpl(): _scope(0)
{
std::memset(&_addr, 0, sizeof(_addr));
}
IPv6AddressImpl::IPv6AddressImpl(const void* addr): _scope(0)
{
std::memcpy(&_addr, addr, sizeof(_addr));
}
IPv6AddressImpl::IPv6AddressImpl(const void* addr, Poco::UInt32 scope): _scope(scope)
{
std::memcpy(&_addr, addr, sizeof(_addr));
}
IPv6AddressImpl::IPv6AddressImpl(const IPv6AddressImpl& addr): _scope(addr._scope)
{
std::memcpy((void*) &_addr, (void*) &addr._addr, sizeof(_addr));
}
IPv6AddressImpl& IPv6AddressImpl::operator = (const IPv6AddressImpl& addr)
{
if (this == &addr)
return *this;
_scope = addr._scope;
std::memcpy(&_addr, &addr._addr, sizeof(_addr));
return *this;
}
IPv6AddressImpl::IPv6AddressImpl(unsigned prefix):
_scope(0)
{
unsigned i = 0;
#ifdef POCO_OS_FAMILY_WINDOWS
for (; prefix >= 16; ++i, prefix -= 16)
{
_addr.s6_addr16[i] = 0xffff;
}
if (prefix > 0)
{
_addr.s6_addr16[i++] = ByteOrder::toNetwork(static_cast<Poco::UInt16>(~(0xffff >> prefix)));
}
while (i < 8)
{
_addr.s6_addr16[i++] = 0;
}
#else
for (; prefix >= 32; ++i, prefix -= 32)
{
_addr.s6_addr32[i] = 0xffffffff;
}
if (prefix > 0)
{
_addr.s6_addr32[i++] = ByteOrder::toNetwork(~(0xffffffffU >> prefix));
}
while (i < 4)
{
_addr.s6_addr32[i++] = 0;
}
#endif
}
std::string IPv6AddressImpl::toString() const
{
const UInt16* words = reinterpret_cast<const UInt16*>(&_addr);
if ((isIPv4Compatible() && !isLoopback()) || isIPv4Mapped())
{
std::string result;
result.reserve(24);
if (words[5] == 0)
result.append("::");
else
result.append("::ffff:");
const UInt8* bytes = reinterpret_cast<const UInt8*>(&_addr);
if (bytes[12] != 0) // only 0.0.0.0 can start with zero
{
NumberFormatter::append(result, bytes[12]);
result.append(".");
NumberFormatter::append(result, bytes[13]);
result.append(".");
NumberFormatter::append(result, bytes[14]);
result.append(".");
NumberFormatter::append(result, bytes[15]);
}
return result;
}
else
{
std::string result;
result.reserve(64);
bool zeroSequence = false;
int i = 0;
while (i < 8)
{
if (!zeroSequence && words[i] == 0)
{
int zi = i;
while (zi < 8 && words[zi] == 0) ++zi;
if (zi > i + 1)
{
i = zi;
result.append(":");
zeroSequence = true;
}
}
if (i > 0) result.append(":");
if (i < 8) NumberFormatter::appendHex(result, ByteOrder::fromNetwork(words[i++]));
}
if (_scope > 0)
{
result.append("%");
#if defined(_WIN32)
NumberFormatter::append(result, _scope);
#else
char buffer[IFNAMSIZ];
if (if_indextoname(_scope, buffer))
{
result.append(buffer);
}
else
{
NumberFormatter::append(result, _scope);
}
#endif
}
return toLower(result);
}
}
poco_socklen_t IPv6AddressImpl::length() const
{
return sizeof(_addr);
}
const void* IPv6AddressImpl::addr() const
{
return &_addr;
}
IPAddressImpl::Family IPv6AddressImpl::family() const
{
return AddressFamily::IPv6;
}
int IPv6AddressImpl::af() const
{
return AF_INET6;
}
unsigned IPv6AddressImpl::prefixLength() const
{
unsigned bits = 0;
unsigned bitPos = 128;
#if defined(POCO_OS_FAMILY_UNIX)
for (int i = 3; i >= 0; --i)
{
unsigned addr = ntohl(_addr.s6_addr32[i]);
if ((bits = maskBits(addr, 32))) return (bitPos - (32 - bits));
bitPos -= 32;
}
return 0;
#elif defined(POCO_OS_FAMILY_WINDOWS)
for (int i = 7; i >= 0; --i)
{
unsigned short addr = ByteOrder::fromNetwork(_addr.s6_addr16[i]);
if ((bits = maskBits(addr, 16))) return (bitPos - (16 - bits));
bitPos -= 16;
}
return 0;
#else
#warning prefixLength() not implemented
throw NotImplementedException("prefixLength() not implemented");
#endif
}
Poco::UInt32 IPv6AddressImpl::scope() const
{
return _scope;
}
bool IPv6AddressImpl::isWildcard() const
{
const UInt16* words = reinterpret_cast<const UInt16*>(&_addr);
return words[0] == 0 && words[1] == 0 && words[2] == 0 && words[3] == 0 &&
words[4] == 0 && words[5] == 0 && words[6] == 0 && words[7] == 0;
}
bool IPv6AddressImpl::isBroadcast() const
{
return false;
}
bool IPv6AddressImpl::isLoopback() const
{
const UInt16* words = reinterpret_cast<const UInt16*>(&_addr);
return words[0] == 0 && words[1] == 0 && words[2] == 0 && words[3] == 0 &&
words[4] == 0 && words[5] == 0 && words[6] == 0 && ByteOrder::fromNetwork(words[7]) == 0x0001;
}
bool IPv6AddressImpl::isMulticast() const
{
const UInt16* words = reinterpret_cast<const UInt16*>(&_addr);
return (ByteOrder::fromNetwork(words[0]) & 0xFFE0) == 0xFF00;
}
bool IPv6AddressImpl::isLinkLocal() const
{
const UInt16* words = reinterpret_cast<const UInt16*>(&_addr);
return (ByteOrder::fromNetwork(words[0]) & 0xFFE0) == 0xFE80;
}
bool IPv6AddressImpl::isSiteLocal() const
{
const UInt16* words = reinterpret_cast<const UInt16*>(&_addr);
return ((ByteOrder::fromNetwork(words[0]) & 0xFFE0) == 0xFEC0) || ((ByteOrder::fromNetwork(words[0]) & 0xFF00) == 0xFC00);
}
bool IPv6AddressImpl::isIPv4Compatible() const
{
const UInt16* words = reinterpret_cast<const UInt16*>(&_addr);
return words[0] == 0 && words[1] == 0 && words[2] == 0 && words[3] == 0 && words[4] == 0 && words[5] == 0;
}
bool IPv6AddressImpl::isIPv4Mapped() const
{
const UInt16* words = reinterpret_cast<const UInt16*>(&_addr);
return words[0] == 0 && words[1] == 0 && words[2] == 0 && words[3] == 0 && words[4] == 0 && ByteOrder::fromNetwork(words[5]) == 0xFFFF;
}
bool IPv6AddressImpl::isWellKnownMC() const
{
const UInt16* words = reinterpret_cast<const UInt16*>(&_addr);
return (ByteOrder::fromNetwork(words[0]) & 0xFFF0) == 0xFF00;
}
bool IPv6AddressImpl::isNodeLocalMC() const
{
const UInt16* words = reinterpret_cast<const UInt16*>(&_addr);
return (ByteOrder::fromNetwork(words[0]) & 0xFFEF) == 0xFF01;
}
bool IPv6AddressImpl::isLinkLocalMC() const
{
const UInt16* words = reinterpret_cast<const UInt16*>(&_addr);
return (ByteOrder::fromNetwork(words[0]) & 0xFFEF) == 0xFF02;
}
bool IPv6AddressImpl::isSiteLocalMC() const
{
const UInt16* words = reinterpret_cast<const UInt16*>(&_addr);
return (ByteOrder::fromNetwork(words[0]) & 0xFFEF) == 0xFF05;
}
bool IPv6AddressImpl::isOrgLocalMC() const
{
const UInt16* words = reinterpret_cast<const UInt16*>(&_addr);
return (ByteOrder::fromNetwork(words[0]) & 0xFFEF) == 0xFF08;
}
bool IPv6AddressImpl::isGlobalMC() const
{
const UInt16* words = reinterpret_cast<const UInt16*>(&_addr);
return (ByteOrder::fromNetwork(words[0]) & 0xFFEF) == 0xFF0F;
}
IPv6AddressImpl IPv6AddressImpl::parse(const std::string& addr)
{
if (addr.empty()) return IPv6AddressImpl();
#if defined(_WIN32)
struct addrinfo* pAI;
struct addrinfo hints;
std::memset(&hints, 0, sizeof(hints));
hints.ai_flags = AI_NUMERICHOST;
int rc = getaddrinfo(addr.c_str(), NULL, &hints, &pAI);
if (rc == 0)
{
IPv6AddressImpl result = IPv6AddressImpl(&reinterpret_cast<struct sockaddr_in6*>(pAI->ai_addr)->sin6_addr, static_cast<int>(reinterpret_cast<struct sockaddr_in6*>(pAI->ai_addr)->sin6_scope_id));
freeaddrinfo(pAI);
return result;
}
else return IPv6AddressImpl();
#else
struct in6_addr ia;
std::string::size_type pos = addr.find('%');
if (std::string::npos != pos)
{
std::string::size_type start = ('[' == addr[0]) ? 1 : 0;
std::string unscopedAddr(addr, start, pos - start);
std::string scope(addr, pos + 1, addr.size() - start - pos);
Poco::UInt32 scopeId(0);
if (!(scopeId = if_nametoindex(scope.c_str())))
return IPv6AddressImpl();
if (inet_pton(AF_INET6, unscopedAddr.c_str(), &ia) == 1)
return IPv6AddressImpl(&ia, scopeId);
else
return IPv6AddressImpl();
}
else
{
if (inet_pton(AF_INET6, addr.c_str(), &ia) == 1)
return IPv6AddressImpl(&ia);
else
return IPv6AddressImpl();
}
#endif
}
void IPv6AddressImpl::mask(const IPAddressImpl* pMask, const IPAddressImpl* pSet)
{
throw Poco::NotImplementedException("mask() is only supported for IPv4 addresses");
}
IPAddressImpl* IPv6AddressImpl::clone() const
{
return new IPv6AddressImpl(*this);
}
IPv6AddressImpl IPv6AddressImpl::operator & (const IPv6AddressImpl& addr) const
{
if (_scope != addr._scope)
throw Poco::InvalidArgumentException("Scope ID of passed IPv6 address does not match with the source one.");
IPv6AddressImpl result(*this);
#ifdef POCO_OS_FAMILY_WINDOWS
result._addr.s6_addr16[0] &= addr._addr.s6_addr16[0];
result._addr.s6_addr16[1] &= addr._addr.s6_addr16[1];
result._addr.s6_addr16[2] &= addr._addr.s6_addr16[2];
result._addr.s6_addr16[3] &= addr._addr.s6_addr16[3];
result._addr.s6_addr16[4] &= addr._addr.s6_addr16[4];
result._addr.s6_addr16[5] &= addr._addr.s6_addr16[5];
result._addr.s6_addr16[6] &= addr._addr.s6_addr16[6];
result._addr.s6_addr16[7] &= addr._addr.s6_addr16[7];
#else
result._addr.s6_addr32[0] &= addr._addr.s6_addr32[0];
result._addr.s6_addr32[1] &= addr._addr.s6_addr32[1];
result._addr.s6_addr32[2] &= addr._addr.s6_addr32[2];
result._addr.s6_addr32[3] &= addr._addr.s6_addr32[3];
#endif
return result;
}
IPv6AddressImpl IPv6AddressImpl::operator | (const IPv6AddressImpl& addr) const
{
if (_scope != addr._scope)
throw Poco::InvalidArgumentException("Scope ID of passed IPv6 address does not match with the source one.");
IPv6AddressImpl result(*this);
#ifdef POCO_OS_FAMILY_WINDOWS
result._addr.s6_addr16[0] |= addr._addr.s6_addr16[0];
result._addr.s6_addr16[1] |= addr._addr.s6_addr16[1];
result._addr.s6_addr16[2] |= addr._addr.s6_addr16[2];
result._addr.s6_addr16[3] |= addr._addr.s6_addr16[3];
result._addr.s6_addr16[4] |= addr._addr.s6_addr16[4];
result._addr.s6_addr16[5] |= addr._addr.s6_addr16[5];
result._addr.s6_addr16[6] |= addr._addr.s6_addr16[6];
result._addr.s6_addr16[7] |= addr._addr.s6_addr16[7];
#else
result._addr.s6_addr32[0] |= addr._addr.s6_addr32[0];
result._addr.s6_addr32[1] |= addr._addr.s6_addr32[1];
result._addr.s6_addr32[2] |= addr._addr.s6_addr32[2];
result._addr.s6_addr32[3] |= addr._addr.s6_addr32[3];
#endif
return result;
}
IPv6AddressImpl IPv6AddressImpl::operator ^ (const IPv6AddressImpl& addr) const
{
if (_scope != addr._scope)
throw Poco::InvalidArgumentException("Scope ID of passed IPv6 address does not match with the source one.");
IPv6AddressImpl result(*this);
#ifdef POCO_OS_FAMILY_WINDOWS
result._addr.s6_addr16[0] ^= addr._addr.s6_addr16[0];
result._addr.s6_addr16[1] ^= addr._addr.s6_addr16[1];
result._addr.s6_addr16[2] ^= addr._addr.s6_addr16[2];
result._addr.s6_addr16[3] ^= addr._addr.s6_addr16[3];
result._addr.s6_addr16[4] ^= addr._addr.s6_addr16[4];
result._addr.s6_addr16[5] ^= addr._addr.s6_addr16[5];
result._addr.s6_addr16[6] ^= addr._addr.s6_addr16[6];
result._addr.s6_addr16[7] ^= addr._addr.s6_addr16[7];
#else
result._addr.s6_addr32[0] ^= addr._addr.s6_addr32[0];
result._addr.s6_addr32[1] ^= addr._addr.s6_addr32[1];
result._addr.s6_addr32[2] ^= addr._addr.s6_addr32[2];
result._addr.s6_addr32[3] ^= addr._addr.s6_addr32[3];
#endif
return result;
}
IPv6AddressImpl IPv6AddressImpl::operator ~ () const
{
IPv6AddressImpl result(*this);
#ifdef POCO_OS_FAMILY_WINDOWS
result._addr.s6_addr16[0] ^= 0xffff;
result._addr.s6_addr16[1] ^= 0xffff;
result._addr.s6_addr16[2] ^= 0xffff;
result._addr.s6_addr16[3] ^= 0xffff;
result._addr.s6_addr16[4] ^= 0xffff;
result._addr.s6_addr16[5] ^= 0xffff;
result._addr.s6_addr16[6] ^= 0xffff;
result._addr.s6_addr16[7] ^= 0xffff;
#else
result._addr.s6_addr32[0] ^= 0xffffffff;
result._addr.s6_addr32[1] ^= 0xffffffff;
result._addr.s6_addr32[2] ^= 0xffffffff;
result._addr.s6_addr32[3] ^= 0xffffffff;
#endif
return result;
}
bool IPv6AddressImpl::operator == (const IPv6AddressImpl& addr) const
{
return _scope == addr._scope && 0 == std::memcmp(&addr._addr, &_addr, sizeof(_addr));
}
bool IPv6AddressImpl::operator != (const IPv6AddressImpl& addr) const
{
return !(*this == addr);
}
#endif // POCO_HAVE_IPv6
} } } // namespace Poco::Net::Impl
+748
View File
@@ -0,0 +1,748 @@
//
// MailMessage.cpp
//
// Library: Net
// Package: Mail
// Module: MailMessage
//
// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/MailMessage.h"
#include "Poco/Net/MediaType.h"
#include "Poco/Net/MultipartReader.h"
#include "Poco/Net/MultipartWriter.h"
#include "Poco/Net/PartSource.h"
#include "Poco/Net/PartHandler.h"
#include "Poco/Net/StringPartSource.h"
#include "Poco/Net/QuotedPrintableEncoder.h"
#include "Poco/Net/QuotedPrintableDecoder.h"
#include "Poco/Net/NameValueCollection.h"
#include "Poco/Base64Encoder.h"
#include "Poco/Base64Decoder.h"
#include "Poco/StreamCopier.h"
#include "Poco/DateTimeFormat.h"
#include "Poco/DateTimeFormatter.h"
#include "Poco/DateTimeParser.h"
#include "Poco/String.h"
#include "Poco/StringTokenizer.h"
#include "Poco/StreamCopier.h"
#include "Poco/NumberFormatter.h"
#include <sstream>
using Poco::Base64Encoder;
using Poco::Base64Decoder;
using Poco::StreamCopier;
using Poco::DateTimeFormat;
using Poco::DateTimeFormatter;
using Poco::DateTimeParser;
using Poco::StringTokenizer;
using Poco::icompare;
namespace Poco {
namespace Net {
namespace
{
class MultiPartHandler: public PartHandler
/// This is a default part handler for multipart messages, used when there
/// is no external handler provided to he MailMessage. This handler
/// will handle all types of message parts, including attachments.
{
public:
MultiPartHandler(MailMessage* pMsg): _pMsg(pMsg)
/// Creates multi part handler.
/// The pMsg pointer points to the calling MailMessage
/// and will be used to properly populate it, so the
/// message content could be written out unmodified
/// in its entirety, including attachments.
{
}
~MultiPartHandler()
/// Destroys string part handler.
{
}
void handlePart(const MessageHeader& header, std::istream& stream)
/// Handles a part. If message pointer was provided at construction time,
/// the message pointed to will be properly populated so it could be written
/// back out at a later point in time.
{
std::string tmp;
Poco::StreamCopier::copyToString(stream, tmp);
if (_pMsg)
{
MailMessage::ContentTransferEncoding cte = MailMessage::ENCODING_7BIT;
if (header.has(MailMessage::HEADER_CONTENT_TRANSFER_ENCODING))
{
std::string enc = header[MailMessage::HEADER_CONTENT_TRANSFER_ENCODING];
if (enc == MailMessage::CTE_8BIT)
cte = MailMessage::ENCODING_8BIT;
else if (enc == MailMessage::CTE_QUOTED_PRINTABLE)
cte = MailMessage::ENCODING_QUOTED_PRINTABLE;
else if (enc == MailMessage::CTE_BASE64)
cte = MailMessage::ENCODING_BASE64;
}
std::string contentType = header.get(MailMessage::HEADER_CONTENT_TYPE, "");
std::string contentDisp = header.get(MailMessage::HEADER_CONTENT_DISPOSITION, "");
std::string filename;
if (!contentDisp.empty())
filename = getParamFromHeader(contentDisp, "filename");
if (filename.empty())
filename = getParamFromHeader(contentType, "name");
PartSource* pPS = _pMsg->createPartStore(tmp, contentType, filename);
poco_check_ptr (pPS);
NameValueCollection::ConstIterator it = header.begin();
NameValueCollection::ConstIterator end = header.end();
bool added = false;
for (; it != end; ++it)
{
if (!added && MailMessage::HEADER_CONTENT_DISPOSITION == it->first)
{
if (it->second == "inline")
_pMsg->addContent(pPS, cte);
else
_pMsg->addAttachment("", pPS, cte);
added = true;
}
pPS->headers().set(it->first, it->second);
}
if (contentDisp.empty())
{
_pMsg->addContent(pPS, cte);
added = true;
}
if (!added) delete pPS;
}
}
private:
std::string getParamFromHeader(const std::string& header, const std::string& param)
{
StringTokenizer st(header, ";=", StringTokenizer::TOK_IGNORE_EMPTY | StringTokenizer::TOK_TRIM);
StringTokenizer::Iterator it = st.begin();
StringTokenizer::Iterator end = st.end();
for (; it != end; ++it) { if (*it == param) break; }
if (it != end)
{
++it;
if (it == end) return "";
return *it;
}
return "";
}
MailMessage* _pMsg;
};
class StringPartHandler: public PartHandler
/// This is a default part handler, used when there is no
/// external handler provided to the MailMessage. This handler
/// handles only single-part messages.
{
public:
StringPartHandler(std::string& content): _str(content)
/// Creates string part handler.
/// The content parameter represents the part content.
{
}
~StringPartHandler()
/// Destroys string part handler.
{
}
void handlePart(const MessageHeader& header, std::istream& stream)
/// Handles a part.
{
std::string tmp;
Poco::StreamCopier::copyToString(stream, tmp);
_str.append(tmp);
}
private:
std::string& _str;
};
}
const std::string MailMessage::HEADER_SUBJECT("Subject");
const std::string MailMessage::HEADER_FROM("From");
const std::string MailMessage::HEADER_TO("To");
const std::string MailMessage::HEADER_CC("CC");
const std::string MailMessage::HEADER_BCC("BCC");
const std::string MailMessage::HEADER_DATE("Date");
const std::string MailMessage::HEADER_CONTENT_TYPE("Content-Type");
const std::string MailMessage::HEADER_CONTENT_TRANSFER_ENCODING("Content-Transfer-Encoding");
const std::string MailMessage::HEADER_CONTENT_DISPOSITION("Content-Disposition");
const std::string MailMessage::HEADER_CONTENT_ID("Content-ID");
const std::string MailMessage::HEADER_MIME_VERSION("Mime-Version");
const std::string MailMessage::EMPTY_HEADER;
const std::string MailMessage::TEXT_PLAIN("text/plain");
const std::string MailMessage::CTE_7BIT("7bit");
const std::string MailMessage::CTE_8BIT("8bit");
const std::string MailMessage::CTE_QUOTED_PRINTABLE("quoted-printable");
const std::string MailMessage::CTE_BASE64("base64");
MailMessage::MailMessage(PartStoreFactory* pStoreFactory):
_encoding(),
_pStoreFactory(pStoreFactory)
{
Poco::Timestamp now;
setDate(now);
setContentType("text/plain");
}
MailMessage::~MailMessage()
{
for (auto& part: _parts)
{
delete part.pSource;
}
}
void MailMessage::addRecipient(const MailRecipient& recipient)
{
_recipients.push_back(recipient);
}
void MailMessage::setRecipients(const Recipients& recipients)
{
_recipients.assign(recipients.begin(), recipients.end());
}
void MailMessage::setSender(const std::string& sender)
{
set(HEADER_FROM, sender);
}
const std::string& MailMessage::getSender() const
{
if (has(HEADER_FROM))
return get(HEADER_FROM);
else
return EMPTY_HEADER;
}
void MailMessage::setSubject(const std::string& subject)
{
set(HEADER_SUBJECT, subject);
}
const std::string& MailMessage::getSubject() const
{
if (has(HEADER_SUBJECT))
return get(HEADER_SUBJECT);
else
return EMPTY_HEADER;
}
void MailMessage::setContent(const std::string& content, ContentTransferEncoding encoding)
{
_content = content;
_encoding = encoding;
set(HEADER_CONTENT_TRANSFER_ENCODING, contentTransferEncodingToString(encoding));
}
void MailMessage::setContentType(const std::string& mediaType)
{
set(HEADER_CONTENT_TYPE, mediaType);
}
void MailMessage::setContentType(const MediaType& mediaType)
{
setContentType(mediaType.toString());
}
const std::string& MailMessage::getContentType() const
{
if (has(HEADER_CONTENT_TYPE))
return get(HEADER_CONTENT_TYPE);
else
return TEXT_PLAIN;
}
void MailMessage::setDate(const Poco::Timestamp& dateTime)
{
set(HEADER_DATE, DateTimeFormatter::format(dateTime, DateTimeFormat::RFC1123_FORMAT));
}
Poco::Timestamp MailMessage::getDate() const
{
const std::string& dateTime = get(HEADER_DATE);
int tzd;
return DateTimeParser::parse(dateTime, tzd).timestamp();
}
bool MailMessage::isMultipart() const
{
MediaType mediaType = getContentType();
return mediaType.matches("multipart");
}
void MailMessage::addPart(const std::string& name, PartSource* pSource, ContentDisposition disposition, ContentTransferEncoding encoding)
{
poco_check_ptr (pSource);
makeMultipart();
Part part;
part.name = name;
part.pSource = pSource;
part.disposition = disposition;
part.encoding = encoding;
_parts.push_back(part);
}
void MailMessage::addContent(PartSource* pSource, ContentTransferEncoding encoding)
{
addPart("", pSource, CONTENT_INLINE, encoding);
}
void MailMessage::addAttachment(const std::string& name, PartSource* pSource, ContentTransferEncoding encoding)
{
addPart(name, pSource, CONTENT_ATTACHMENT, encoding);
}
void MailMessage::read(std::istream& istr, PartHandler& handler)
{
readHeader(istr);
if (isMultipart())
{
readMultipart(istr, handler);
}
else
{
StringPartHandler handler(_content);
readPart(istr, *this, handler);
}
}
void MailMessage::read(std::istream& istr)
{
readHeader(istr);
if (isMultipart())
{
MultiPartHandler handler(this);
readMultipart(istr, handler);
}
else
{
StringPartHandler handler(_content);
readPart(istr, *this, handler);
}
}
void MailMessage::write(std::ostream& ostr) const
{
MessageHeader header(*this);
setRecipientHeaders(header);
if (isMultipart())
{
writeMultipart(header, ostr);
}
else
{
writeHeader(header, ostr);
std::istringstream istr(_content);
writeEncoded(istr, ostr, _encoding);
}
}
void MailMessage::makeMultipart()
{
if (!isMultipart())
{
MediaType mediaType("multipart", "mixed");
setContentType(mediaType);
}
}
void MailMessage::writeHeader(const MessageHeader& header, std::ostream& ostr) const
{
header.write(ostr);
ostr << "\r\n";
}
void MailMessage::writeMultipart(MessageHeader& header, std::ostream& ostr) const
{
if (_boundary.empty()) _boundary = MultipartWriter::createBoundary();
MediaType mediaType(getContentType());
mediaType.setParameter("boundary", _boundary);
header.set(HEADER_CONTENT_TYPE, mediaType.toString());
header.set(HEADER_MIME_VERSION, "1.0");
writeHeader(header, ostr);
MultipartWriter writer(ostr, _boundary);
for (const auto& part: _parts)
{
writePart(writer, part);
}
writer.close();
}
void MailMessage::writePart(MultipartWriter& writer, const Part& part)
{
MessageHeader partHeader(part.pSource->headers());
MediaType mediaType(part.pSource->mediaType());
if (!part.name.empty())
mediaType.setParameter("name", part.name);
partHeader.set(HEADER_CONTENT_TYPE, mediaType.toString());
partHeader.set(HEADER_CONTENT_TRANSFER_ENCODING, contentTransferEncodingToString(part.encoding));
std::string disposition;
if (part.disposition == CONTENT_ATTACHMENT)
{
disposition = "attachment";
const std::string& filename = part.pSource->filename();
if (!filename.empty())
{
disposition.append("; filename=");
quote(filename, disposition);
}
}
else disposition = "inline";
partHeader.set(HEADER_CONTENT_DISPOSITION, disposition);
writer.nextPart(partHeader);
writeEncoded(part.pSource->stream(), writer.stream(), part.encoding);
}
void MailMessage::writeEncoded(std::istream& istr, std::ostream& ostr, ContentTransferEncoding encoding)
{
switch (encoding)
{
case ENCODING_7BIT:
case ENCODING_8BIT:
StreamCopier::copyStream(istr, ostr);
break;
case ENCODING_QUOTED_PRINTABLE:
{
QuotedPrintableEncoder encoder(ostr);
StreamCopier::copyStream(istr, encoder);
encoder.close();
}
break;
case ENCODING_BASE64:
{
Base64Encoder encoder(ostr);
StreamCopier::copyStream(istr, encoder);
encoder.close();
}
break;
}
}
void MailMessage::readHeader(std::istream& istr)
{
clear();
MessageHeader::read(istr);
istr.get(); // \r
if ('\n' == istr.peek()) istr.get(); // \n
}
void MailMessage::readMultipart(std::istream& istr, PartHandler& handler)
{
MediaType contentType(getContentType());
_boundary = contentType.getParameter("boundary");
MultipartReader reader(istr, _boundary);
while (reader.hasNextPart())
{
MessageHeader partHeader;
reader.nextPart(partHeader);
readPart(reader.stream(), partHeader, handler);
}
}
void MailMessage::readPart(std::istream& istr, const MessageHeader& header, PartHandler& handler)
{
std::string encoding;
if (header.has(HEADER_CONTENT_TRANSFER_ENCODING))
{
encoding = header.get(HEADER_CONTENT_TRANSFER_ENCODING);
// get rid of a parameter if one is set
std::string::size_type pos = encoding.find(';');
if (pos != std::string::npos)
encoding.resize(pos);
}
if (icompare(encoding, CTE_QUOTED_PRINTABLE) == 0)
{
QuotedPrintableDecoder decoder(istr);
handlePart(decoder, header, handler);
_encoding = ENCODING_QUOTED_PRINTABLE;
}
else if (icompare(encoding, CTE_BASE64) == 0)
{
Base64Decoder decoder(istr);
handlePart(decoder, header, handler);
_encoding = ENCODING_BASE64;
}
else
{
if (icompare(encoding, CTE_7BIT) == 0)
_encoding = ENCODING_7BIT;
else if (icompare(encoding, CTE_8BIT) == 0)
_encoding = ENCODING_8BIT;
handlePart(istr, header, handler);
}
}
void MailMessage::handlePart(std::istream& istr, const MessageHeader& header, PartHandler& handler)
{
handler.handlePart(header, istr);
// Read remaining characters from stream in case
// the handler failed to read the complete stream.
while (istr.good()) istr.get();
}
void MailMessage::setRecipientHeaders(MessageHeader& headers) const
{
std::string to;
std::string cc;
std::string bcc;
for (const auto& rec: _recipients)
{
switch (rec.getType())
{
case MailRecipient::PRIMARY_RECIPIENT:
appendRecipient(rec, to);
break;
case MailRecipient::CC_RECIPIENT:
appendRecipient(rec, cc);
break;
case MailRecipient::BCC_RECIPIENT:
break;
}
}
if (!to.empty()) headers.set(HEADER_TO, to);
if (!cc.empty()) headers.set(HEADER_CC, cc);
}
const std::string& MailMessage::contentTransferEncodingToString(ContentTransferEncoding encoding)
{
switch (encoding)
{
case ENCODING_7BIT:
return CTE_7BIT;
case ENCODING_8BIT:
return CTE_8BIT;
case ENCODING_QUOTED_PRINTABLE:
return CTE_QUOTED_PRINTABLE;
case ENCODING_BASE64:
return CTE_BASE64;
default:
poco_bugcheck();
}
return CTE_7BIT;
}
int MailMessage::lineLength(const std::string& str)
{
int n = 0;
std::string::const_reverse_iterator it = str.rbegin();
std::string::const_reverse_iterator end = str.rend();
while (it != end && *it != '\n') { ++n; ++it; }
return n;
}
void MailMessage::appendRecipient(const MailRecipient& recipient, std::string& str)
{
if (!str.empty()) str.append(", ");
const std::string& realName = recipient.getRealName();
const std::string& address = recipient.getAddress();
std::string rec;
if (!realName.empty())
{
quote(realName, rec, true);
rec.append(" ");
}
rec.append("<");
rec.append(address);
rec.append(">");
if (lineLength(str) + rec.length() > 70) str.append("\r\n\t");
str.append(rec);
}
std::string MailMessage::encodeWord(const std::string& text, const std::string& charset)
{
bool containsNonASCII = false;
for (auto ch: text)
{
if (static_cast<unsigned char>(ch) > 127)
{
containsNonASCII = true;
break;
}
}
if (!containsNonASCII) return text;
std::string encodedText;
std::string::size_type lineLength = 0;
for (auto ch: text)
{
if (lineLength == 0)
{
encodedText += "=?";
encodedText += charset;
encodedText += "?q?";
lineLength += charset.length() + 5;
}
switch (ch)
{
case ' ':
encodedText += '_';
lineLength++;
break;
case '=':
case '?':
case '_':
case '(':
case ')':
case '[':
case ']':
case '<':
case '>':
case ',':
case ';':
case ':':
case '.':
case '@':
encodedText += '=';
NumberFormatter::appendHex(encodedText, static_cast<unsigned>(static_cast<unsigned char>(ch)), 2);
lineLength += 3;
break;
default:
if (ch > 32 && ch < 127)
{
encodedText += ch;
lineLength++;
}
else
{
encodedText += '=';
NumberFormatter::appendHex(encodedText, static_cast<unsigned>(static_cast<unsigned char>(ch)), 2);
lineLength += 3;
}
}
if ((lineLength >= 64 && (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n')) || lineLength >= 72)
{
encodedText += "?=\r\n ";
lineLength = 0;
}
}
if (lineLength > 0)
{
encodedText += "?=";
}
return encodedText;
}
PartSource* MailMessage::createPartStore(const std::string& content, const std::string& mediaType, const std::string& filename)
{
if (!_pStoreFactory) return new StringPartSource(content, mediaType, filename);
else return _pStoreFactory->createPartStore(content, mediaType, filename);
}
MultipartSource::MultipartSource(const std::string contentType):
PartSource(contentTypeWithBoundary(contentType))
{
}
MultipartSource::~MultipartSource()
{
for (auto& part: _parts)
{
delete part.pSource;
}
}
void MultipartSource::addPart(const std::string& name,
PartSource* pSource,
MailMessage::ContentDisposition disposition,
MailMessage::ContentTransferEncoding encoding)
{
MailMessage::Part part;
part.name = name;
part.pSource = pSource;
part.disposition = disposition;
part.encoding = encoding;
_parts.push_back(part);
}
std::istream& MultipartSource::stream()
{
MediaType mt(mediaType());
std::string boundary = mt.getParameter("boundary");
MultipartWriter writer(_content, boundary);
for (const auto& part: _parts)
{
MailMessage::writePart(writer, part);
}
writer.close();
return _content;
}
std::string MultipartSource::contentTypeWithBoundary(const std::string& contentType)
{
MediaType mediaType(contentType);
mediaType.setParameter("boundary", MultipartWriter::createBoundary());
return mediaType.toString();
}
} } // namespace Poco::Net
+94
View File
@@ -0,0 +1,94 @@
//
// MailRecipient.cpp
//
// Library: Net
// Package: Mail
// Module: MailRecipient
//
// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/MailRecipient.h"
#include <algorithm>
namespace Poco {
namespace Net {
MailRecipient::MailRecipient():
_type(PRIMARY_RECIPIENT)
{
}
MailRecipient::MailRecipient(const MailRecipient& recipient):
_address(recipient._address),
_realName(recipient._realName),
_type(recipient._type)
{
}
MailRecipient::MailRecipient(RecipientType type, const std::string& address):
_address(address),
_type(type)
{
}
MailRecipient::MailRecipient(RecipientType type, const std::string& address, const std::string& realName):
_address(address),
_realName(realName),
_type(type)
{
}
MailRecipient::~MailRecipient()
{
}
MailRecipient& MailRecipient::operator = (const MailRecipient& recipient)
{
if (this != &recipient)
{
MailRecipient tmp(recipient);
swap(tmp);
}
return *this;
}
void MailRecipient::swap(MailRecipient& recipient)
{
std::swap(_type, recipient._type);
std::swap(_address, recipient._address);
std::swap(_realName, recipient._realName);
}
void MailRecipient::setType(RecipientType type)
{
_type = type;
}
void MailRecipient::setAddress(const std::string& address)
{
_address = address;
}
void MailRecipient::setRealName(const std::string& realName)
{
_realName = realName;
}
} } // namespace Poco::Net
+221
View File
@@ -0,0 +1,221 @@
//
// MailStream.cpp
//
// Library: Net
// Package: Mail
// Module: MailStream
//
// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/MailStream.h"
namespace Poco {
namespace Net {
MailStreamBuf::MailStreamBuf(std::istream& istr):
_pIstr(&istr),
_pOstr(0),
_state(ST_CR_LF)
{
}
MailStreamBuf::MailStreamBuf(std::ostream& ostr):
_pIstr(0),
_pOstr(&ostr),
_state(ST_CR_LF)
{
}
MailStreamBuf::~MailStreamBuf()
{
}
void MailStreamBuf::close()
{
if (_pOstr && _state != ST_CR_LF_DOT_CR_LF)
{
if (!_buffer.empty())
_pOstr->write(_buffer.data(), (std::streamsize) _buffer.length());
if (_state != ST_CR_LF)
_pOstr->write("\r\n", 2);
_pOstr->write(".\r\n", 3);
_state = ST_CR_LF_DOT_CR_LF;
}
}
int MailStreamBuf::readFromDevice()
{
int c = std::char_traits<char>::eof();
if (!_buffer.empty())
{
c = _buffer[0];
_buffer.erase(0, 1);
}
else
{
c = readOne();
while (c != std::char_traits<char>::eof() && _state != ST_DATA && _state != ST_CR_LF_DOT_CR_LF)
c = readOne();
if (!_buffer.empty())
{
c = _buffer[0];
_buffer.erase(0, 1);
}
}
return c;
}
int MailStreamBuf::readOne()
{
int c = std::char_traits<char>::eof();
if (_state != ST_CR_LF_DOT_CR_LF)
{
c = _pIstr->get();
switch (c)
{
case '\r':
if (_state == ST_CR_LF_DOT)
_state = ST_CR_LF_DOT_CR;
else
_state = ST_CR;
break;
case '\n':
if (_state == ST_CR)
_state = ST_CR_LF;
else if (_state == ST_CR_LF_DOT_CR)
_state = ST_CR_LF_DOT_CR_LF;
else
_state = ST_DATA;
break;
case '.':
if (_state == ST_CR_LF)
_state = ST_CR_LF_DOT;
else if (_state == ST_CR_LF_DOT)
_state = ST_CR_LF_DOT_DOT;
else
_state = ST_DATA;
break;
default:
_state = ST_DATA;
}
if (_state == ST_CR_LF_DOT_DOT)
_state = ST_DATA;
else if (_state == ST_CR_LF_DOT_CR_LF)
_buffer.resize(_buffer.size() - 2);
else if (c != std::char_traits<char>::eof())
_buffer += (char) c;
}
return c;
}
int MailStreamBuf::writeToDevice(char c)
{
switch (c)
{
case '\r':
_state = ST_CR;
break;
case '\n':
if (_state == ST_CR)
_state = ST_CR_LF;
else
_state = ST_DATA;
break;
case '.':
if (_state == ST_CR_LF)
_state = ST_CR_LF_DOT;
else
_state = ST_DATA;
break;
default:
_state = ST_DATA;
}
if (_state == ST_DATA)
{
if (!_buffer.empty())
{
_pOstr->write(_buffer.data(), (std::streamsize) _buffer.length());
_buffer.clear();
}
_pOstr->put(c);
}
else if (_state == ST_CR_LF_DOT)
{
// buffer contains one or more CR-LF pairs
_pOstr->write(_buffer.data(), (std::streamsize) _buffer.length());
_pOstr->write("..", 2);
_state = ST_DATA;
_buffer.clear();
}
else _buffer += c;
return charToInt(c);
}
MailIOS::MailIOS(std::istream& istr): _buf(istr)
{
poco_ios_init(&_buf);
}
MailIOS::MailIOS(std::ostream& ostr): _buf(ostr)
{
poco_ios_init(&_buf);
}
MailIOS::~MailIOS()
{
}
void MailIOS::close()
{
_buf.close();
}
MailStreamBuf* MailIOS::rdbuf()
{
return &_buf;
}
MailInputStream::MailInputStream(std::istream& istr):
MailIOS(istr),
std::istream(&_buf)
{
}
MailInputStream::~MailInputStream()
{
}
MailOutputStream::MailOutputStream(std::ostream& ostr):
MailIOS(ostr),
std::ostream(&_buf)
{
}
MailOutputStream::~MailOutputStream()
{
}
} } // namespace Poco::Net
+210
View File
@@ -0,0 +1,210 @@
//
// MediaType.cpp
//
// Library: Net
// Package: Messages
// Module: MediaType
//
// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/MediaType.h"
#include "Poco/Net/MessageHeader.h"
#include "Poco/String.h"
#include "Poco/Ascii.h"
#include <algorithm>
using Poco::icompare;
namespace Poco {
namespace Net {
MediaType::MediaType(const std::string& mediaType)
{
parse(mediaType);
}
MediaType::MediaType(const std::string& type, const std::string& subType):
_type(type),
_subType(subType)
{
}
MediaType::MediaType(const MediaType& mediaType):
_type(mediaType._type),
_subType(mediaType._subType),
_parameters(mediaType._parameters)
{
}
MediaType::MediaType(MediaType&& mediaType) noexcept:
_type(std::move(mediaType._type)),
_subType(std::move(mediaType._subType)),
_parameters(std::move(mediaType._parameters))
{
}
MediaType::~MediaType()
{
}
MediaType& MediaType::operator = (const MediaType& mediaType)
{
if (&mediaType != this)
{
_type = mediaType._type;
_subType = mediaType._subType;
_parameters = mediaType._parameters;
}
return *this;
}
MediaType& MediaType::operator = (MediaType&& mediaType) noexcept
{
_type = std::move(mediaType._type);
_subType = std::move(mediaType._subType);
_parameters = std::move(mediaType._parameters);
return *this;
}
MediaType& MediaType::operator = (const std::string& mediaType)
{
parse(mediaType);
return *this;
}
void MediaType::swap(MediaType& mediaType)
{
std::swap(_type, mediaType._type);
std::swap(_subType, mediaType._subType);
_parameters.swap(mediaType._parameters);
}
void MediaType::setType(const std::string& type)
{
_type = type;
}
void MediaType::setSubType(const std::string& subType)
{
_subType = subType;
}
void MediaType::setParameter(const std::string& name, const std::string& value)
{
_parameters.set(name, value);
}
const std::string& MediaType::getParameter(const std::string& name) const
{
return _parameters.get(name);
}
bool MediaType::hasParameter(const std::string& name) const
{
return _parameters.has(name);
}
void MediaType::removeParameter(const std::string& name)
{
_parameters.erase(name);
}
std::string MediaType::toString() const
{
std::string result;
result.append(_type);
result.append("/");
result.append(_subType);
for (NameValueCollection::ConstIterator it = _parameters.begin(); it != _parameters.end(); ++it)
{
result.append("; ");
result.append(it->first);
result.append("=");
MessageHeader::quote(it->second, result);
}
return result;
}
bool MediaType::matches(const MediaType& mediaType) const
{
return matches(mediaType._type, mediaType._subType);
}
bool MediaType::matches(const std::string& type, const std::string& subType) const
{
return icompare(_type, type) == 0 && icompare(_subType, subType) == 0;
}
bool MediaType::matches(const std::string& type) const
{
return icompare(_type, type) == 0;
}
bool MediaType::matchesRange(const MediaType& mediaType) const
{
return matchesRange(mediaType._type, mediaType._subType);
}
bool MediaType::matchesRange(const std::string& type, const std::string& subType) const
{
if (_type == "*" || type == "*" || icompare(_type, type) == 0)
{
return _subType == "*" || subType == "*" || icompare(_subType, subType) == 0;
}
else return false;
}
bool MediaType::matchesRange(const std::string& type) const
{
return _type == "*" || type == "*" || matches(type);
}
void MediaType::parse(const std::string& mediaType)
{
_type.clear();
_subType.clear();
_parameters.clear();
std::string::const_iterator it = mediaType.begin();
std::string::const_iterator end = mediaType.end();
while (it != end && Poco::Ascii::isSpace(*it)) ++it;
while (it != end && *it != '/') _type += *it++;
if (it != end) ++it;
while (it != end && *it != ';' && !Poco::Ascii::isSpace(*it)) _subType += *it++;
while (it != end && *it != ';') ++it;
if (it != end) ++it; // skip semicolon
MessageHeader::splitParameters(it, end, _parameters);
}
} } // namespace Poco::Net
+394
View File
@@ -0,0 +1,394 @@
//
// MessageHeader.cpp
//
// Library: Net
// Package: Messages
// Module: MessageHeader
//
// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/MessageHeader.h"
#include "Poco/Net/NetException.h"
#include "Poco/String.h"
#include "Poco/Ascii.h"
#include "Poco/TextConverter.h"
#include "Poco/StringTokenizer.h"
#include "Poco/Base64Decoder.h"
#include "Poco/UTF8Encoding.h"
#include <sstream>
namespace Poco {
namespace Net {
MessageHeader::MessageHeader():
_fieldLimit(DFL_FIELD_LIMIT)
{
}
MessageHeader::MessageHeader(const MessageHeader& messageHeader):
NameValueCollection(messageHeader),
_fieldLimit(DFL_FIELD_LIMIT)
{
}
MessageHeader::~MessageHeader()
{
}
MessageHeader& MessageHeader::operator = (const MessageHeader& messageHeader)
{
NameValueCollection::operator = (messageHeader);
return *this;
}
void MessageHeader::write(std::ostream& ostr) const
{
NameValueCollection::ConstIterator it = begin();
while (it != end())
{
ostr << it->first << ": " << it->second << "\r\n";
++it;
}
}
void MessageHeader::read(std::istream& istr)
{
static const int eof = std::char_traits<char>::eof();
std::streambuf& buf = *istr.rdbuf();
std::string name;
std::string value;
name.reserve(32);
value.reserve(64);
int ch = buf.sbumpc();
int fields = 0;
while (ch != eof && ch != '\r' && ch != '\n')
{
if (_fieldLimit > 0 && fields == _fieldLimit)
throw MessageException("Too many header fields");
name.clear();
value.clear();
while (ch != eof && ch != ':' && ch != '\n' && name.length() < MAX_NAME_LENGTH) { name += ch; ch = buf.sbumpc(); }
if (ch == '\n') { ch = buf.sbumpc(); continue; } // ignore invalid header lines
if (ch != ':') throw MessageException("Field name too long/no colon found");
if (ch != eof) ch = buf.sbumpc(); // ':'
while (ch != eof && Poco::Ascii::isSpace(ch) && ch != '\r' && ch != '\n') ch = buf.sbumpc();
while (ch != eof && ch != '\r' && ch != '\n' && value.length() < MAX_VALUE_LENGTH) { value += ch; ch = buf.sbumpc(); }
if (ch == '\r') ch = buf.sbumpc();
if (ch == '\n')
ch = buf.sbumpc();
else if (ch != eof)
throw MessageException("Field value too long/no CRLF found");
while (ch == ' ' || ch == '\t') // folding
{
while (ch != eof && ch != '\r' && ch != '\n' && value.length() < MAX_VALUE_LENGTH) { value += ch; ch = buf.sbumpc(); }
if (ch == '\r') ch = buf.sbumpc();
if (ch == '\n')
ch = buf.sbumpc();
else if (ch != eof)
throw MessageException("Folded field value too long/no CRLF found");
}
Poco::trimRightInPlace(value);
add(name, decodeWord(value));
++fields;
}
istr.putback(ch);
}
int MessageHeader::getFieldLimit() const
{
return _fieldLimit;
}
void MessageHeader::setFieldLimit(int limit)
{
poco_assert (limit >= 0);
_fieldLimit = limit;
}
bool MessageHeader::hasToken(const std::string& fieldName, const std::string& token) const
{
std::string field = get(fieldName, "");
std::vector<std::string> tokens;
splitElements(field, tokens, true);
for (const auto& t: tokens)
{
if (Poco::icompare(t, token) == 0)
return true;
}
return false;
}
void MessageHeader::splitElements(const std::string& s, std::vector<std::string>& elements, bool ignoreEmpty)
{
elements.clear();
std::string::const_iterator it = s.begin();
std::string::const_iterator end = s.end();
std::string elem;
elem.reserve(64);
while (it != end)
{
if (*it == '"')
{
elem += *it++;
while (it != end && *it != '"')
{
if (*it == '\\')
{
++it;
if (it != end) elem += *it++;
}
else elem += *it++;
}
if (it != end) elem += *it++;
}
else if (*it == '\\')
{
++it;
if (it != end) elem += *it++;
}
else if (*it == ',')
{
Poco::trimInPlace(elem);
if (!ignoreEmpty || !elem.empty())
elements.push_back(elem);
elem.clear();
++it;
}
else elem += *it++;
}
if (!elem.empty())
{
Poco::trimInPlace(elem);
if (!ignoreEmpty || !elem.empty())
elements.push_back(elem);
}
}
void MessageHeader::splitParameters(const std::string& s, std::string& value, NameValueCollection& parameters)
{
value.clear();
parameters.clear();
std::string::const_iterator it = s.begin();
std::string::const_iterator end = s.end();
while (it != end && Poco::Ascii::isSpace(*it)) ++it;
while (it != end && *it != ';') value += *it++;
Poco::trimRightInPlace(value);
if (it != end) ++it;
splitParameters(it, end, parameters);
}
void MessageHeader::splitParameters(const std::string::const_iterator& begin, const std::string::const_iterator& end, NameValueCollection& parameters)
{
std::string pname;
std::string pvalue;
pname.reserve(32);
pvalue.reserve(64);
std::string::const_iterator it = begin;
while (it != end)
{
pname.clear();
pvalue.clear();
while (it != end && Poco::Ascii::isSpace(*it)) ++it;
while (it != end && *it != '=' && *it != ';') pname += *it++;
Poco::trimRightInPlace(pname);
if (it != end && *it != ';') ++it;
while (it != end && Poco::Ascii::isSpace(*it)) ++it;
while (it != end && *it != ';')
{
if (*it == '"')
{
++it;
while (it != end && *it != '"')
{
if (*it == '\\')
{
++it;
if (it != end) pvalue += *it++;
}
else pvalue += *it++;
}
if (it != end) ++it;
}
else if (*it == '\\')
{
++it;
if (it != end) pvalue += *it++;
}
else pvalue += *it++;
}
Poco::trimRightInPlace(pvalue);
if (!pname.empty()) parameters.add(pname, pvalue);
if (it != end) ++it;
}
}
void MessageHeader::quote(const std::string& value, std::string& result, bool allowSpace)
{
bool mustQuote = false;
for (std::string::const_iterator it = value.begin(); !mustQuote && it != value.end(); ++it)
{
if (!Poco::Ascii::isAlphaNumeric(*it) && *it != '.' && *it != '_' && *it != '-' && !(Poco::Ascii::isSpace(*it) && allowSpace))
mustQuote = true;
}
if (mustQuote) result += '"';
result.append(value);
if (mustQuote) result += '"';
}
void MessageHeader::decodeRFC2047(const std::string& ins, std::string& outs, const std::string& charset_to)
{
std::string tempout;
StringTokenizer tokens(ins, "?");
std::string charset = toUpper(tokens[0]);
std::string encoding = toUpper(tokens[1]);
std::string text = tokens[2];
std::istringstream istr(text);
if (encoding == "B")
{
// Base64 encoding.
Base64Decoder decoder(istr);
for (char c; decoder.get(c); tempout += c) {}
}
else if (encoding == "Q")
{
// Quoted encoding.
for (char c; istr.get(c);)
{
if (c == '_')
{
//RFC 2047 _ is a space.
tempout += " ";
continue;
}
// FIXME: check that we have enought chars-
if (c == '=')
{
// The next two chars are hex representation of the complete byte.
std::string hex;
for (int i = 0; i < 2; i++)
{
istr.get(c);
hex += c;
}
hex = toUpper(hex);
tempout += (char)(int)strtol(hex.c_str(), 0, 16);
continue;
}
tempout += c;
}
}
else
{
// Wrong encoding
outs = ins;
return;
}
// convert to the right charset.
if (charset != charset_to)
{
try
{
TextEncoding& enc = TextEncoding::byName(charset);
TextEncoding& dec = TextEncoding::byName(charset_to);
TextConverter converter(enc, dec);
converter.convert(tempout, outs);
}
catch (...)
{
// FIXME: Unsuported encoding...
outs = tempout;
}
}
else
{
// Not conversion necesary.
outs = tempout;
}
}
std::string MessageHeader::decodeWord(const std::string& text, const std::string& charset)
{
std::string outs, tmp = text;
do {
std::string tmp2;
// find the begining of the next rfc2047 chunk
size_t pos = tmp.find("=?");
if (pos == std::string::npos) {
// No more found, return
outs += tmp;
break;
}
// check if there are standar text before the rfc2047 chunk, and if so, copy it.
if (pos > 0) {
outs += tmp.substr(0, pos);
}
// remove text already copied.
tmp = tmp.substr(pos + 2);
// find the first separator
size_t pos1 = tmp.find("?");
if (pos1 == std::string::npos) {
// not found.
outs += tmp;
break;
}
// find the second separator
size_t pos2 = tmp.find("?", pos1 + 1);
if (pos2 == std::string::npos) {
// not found
outs += tmp;
break;
}
// find the end of the actual rfc2047 chunk
size_t pos3 = tmp.find("?=", pos2 + 1);
if (pos3 == std::string::npos) {
// not found.
outs += tmp;
break;
}
// At this place, there are a valid rfc2047 chunk, so decode and copy the result.
decodeRFC2047(tmp.substr(0, pos3), tmp2, charset);
outs += tmp2;
// Jump at the rest of the string and repeat the whole process.
tmp = tmp.substr(pos3 + 2);
} while (true);
return outs;
}
} } // namespace Poco::Net
+289
View File
@@ -0,0 +1,289 @@
//
// MulticastSocket.cpp
//
// Library: Net
// Package: Sockets
// Module: MulticastSocket
//
// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/MulticastSocket.h"
#ifdef POCO_NET_HAS_INTERFACE
#include "Poco/Net/NetException.h"
#include <cstring>
#if defined(hpux) && defined(_XOPEN_SOURCE_EXTENDED) && defined(POCO_HPUX_IP_MREQ_HACK)
// netinet/in.h does not define struct ip_mreq if
// _XOPEN_SOURCE_EXTENDED is #define'd in HP-UX 11.x
// versions prior to 11.30. Compile with -DPOCO_HPUX_IP_MREQ_HACK
// if you experience problems.
struct ip_mreq
{
struct in_addr imr_multiaddr;
struct in_addr imr_interface;
};
#endif
// some Unix variants don't have IPV6_ADD_MEMBERSHIP/IPV6_DROP_MEMBERSHIP
#if defined(IPV6_JOIN_GROUP) && !defined(IPV6_ADD_MEMBERSHIP)
#define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP
#define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP
#endif
namespace Poco {
namespace Net {
MulticastSocket::MulticastSocket()
{
}
MulticastSocket::MulticastSocket(SocketAddress::Family family): DatagramSocket(family)
{
#if defined(POCO_OS_FAMILY_UNIX)
if (family == SocketAddress::UNIX_LOCAL)
throw Poco::InvalidArgumentException("Cannot create a MulticastSocket with UNIX_LOCAL socket");
#endif
}
MulticastSocket::MulticastSocket(const SocketAddress& address, bool reuseAddress): DatagramSocket(address, reuseAddress)
{
}
MulticastSocket::MulticastSocket(const Socket& socket): DatagramSocket(socket)
{
}
MulticastSocket::~MulticastSocket()
{
}
MulticastSocket& MulticastSocket::operator = (const Socket& socket)
{
DatagramSocket::operator = (socket);
return *this;
}
void MulticastSocket::setInterface(const NetworkInterface& interfc)
{
if (address().family() == SocketAddress::IPv4)
{
impl()->setOption(IPPROTO_IP, IP_MULTICAST_IF, interfc.firstAddress(IPAddress::IPv4));
}
#if defined(POCO_HAVE_IPv6)
else if (address().family() == SocketAddress::IPv6)
{
impl()->setOption(IPPROTO_IPV6, IPV6_MULTICAST_IF, interfc.index());
}
#endif
else throw UnsupportedFamilyException("Unknown or unsupported socket family.");
}
NetworkInterface MulticastSocket::getInterface() const
{
try
{
IPAddress addr;
impl()->getOption(IPPROTO_IP, IP_MULTICAST_IF, addr);
return NetworkInterface::forAddress(addr);
}
catch (Poco::Exception&)
{
#if defined(POCO_HAVE_IPv6)
int ix;
impl()->getOption(IPPROTO_IPV6, IPV6_MULTICAST_IF, ix);
return NetworkInterface::forIndex(ix);
#else
throw;
#endif
}
}
void MulticastSocket::setLoopback(bool flag)
{
if (address().af() == AF_INET)
{
unsigned char uflag = flag ? 1 : 0;
impl()->setOption(IPPROTO_IP, IP_MULTICAST_LOOP, uflag);
}
else
{
#if defined(POCO_HAVE_IPv6)
unsigned uflag = flag ? 1 : 0;
impl()->setOption(IPPROTO_IPV6, IPV6_MULTICAST_LOOP, uflag);
#endif
}
}
bool MulticastSocket::getLoopback() const
{
bool flag = false;
if (address().af() == AF_INET)
{
unsigned char uflag;
impl()->getOption(IPPROTO_IP, IP_MULTICAST_LOOP, uflag);
flag = uflag != 0;
}
else
{
#if defined(POCO_HAVE_IPv6)
unsigned uflag;
impl()->getOption(IPPROTO_IPV6, IPV6_MULTICAST_LOOP, uflag);
flag = uflag != 0;
#endif
}
return flag;
}
void MulticastSocket::setTimeToLive(unsigned value)
{
if (address().af() == AF_INET)
{
unsigned char ttl = (unsigned char) value;
impl()->setOption(IPPROTO_IP, IP_MULTICAST_TTL, ttl);
}
else
{
#if defined(POCO_HAVE_IPv6)
impl()->setOption(IPPROTO_IPV6, IPV6_MULTICAST_HOPS, value);
#endif
}
}
unsigned MulticastSocket::getTimeToLive() const
{
unsigned ttl(0);
if (address().af() == AF_INET)
{
unsigned char cttl;
impl()->getOption(IPPROTO_IP, IP_MULTICAST_TTL, cttl);
ttl = cttl;
}
else
{
#if defined(POCO_HAVE_IPv6)
impl()->getOption(IPPROTO_IPV6, IPV6_MULTICAST_HOPS, ttl);
#endif
}
return ttl;
}
void MulticastSocket::joinGroup(const IPAddress& groupAddress)
{
joinGroup(groupAddress, findFirstInterface(groupAddress));
}
void MulticastSocket::joinGroup(const IPAddress& groupAddress, const NetworkInterface& interfc)
{
if (groupAddress.af() == AF_INET)
{
struct ip_mreq mr;
std::memcpy(&mr.imr_multiaddr, groupAddress.addr(), groupAddress.length());
std::memcpy(&mr.imr_interface, interfc.firstAddress(IPAddress::IPv4).addr(), interfc.firstAddress(IPAddress::IPv4).length());
impl()->setRawOption(IPPROTO_IP, IP_ADD_MEMBERSHIP, &mr, sizeof(mr));
}
else
{
#if defined(POCO_HAVE_IPv6)
struct ipv6_mreq mr;
std::memcpy(&mr.ipv6mr_multiaddr, groupAddress.addr(), groupAddress.length());
mr.ipv6mr_interface = interfc.index();
impl()->setRawOption(IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mr, sizeof(mr));
#endif
}
}
NetworkInterface MulticastSocket::findFirstInterface(const IPAddress& groupAddress)
{
NetworkInterface::Map m = NetworkInterface::map();
if (groupAddress.family() == IPAddress::IPv4)
{
for (const auto& p: m)
{
if (p.second.supportsIPv4() &&
p.second.firstAddress(IPAddress::IPv4).isUnicast() &&
!p.second.isLoopback() &&
!p.second.isPointToPoint())
{
return p.second;
}
}
}
#ifdef POCO_HAVE_IPv6
else if (groupAddress.family() == IPAddress::IPv6)
{
for (const auto& p: m)
{
if (p.second.supportsIPv6() &&
p.second.firstAddress(IPAddress::IPv6).isUnicast() &&
!p.second.isLoopback() &&
!p.second.isPointToPoint())
{
return p.second;
}
}
}
#endif // POCO_HAVE_IPv6
throw NotFoundException("No multicast-eligible network interface found.");
}
void MulticastSocket::leaveGroup(const IPAddress& groupAddress)
{
NetworkInterface intf;
leaveGroup(groupAddress, intf);
}
void MulticastSocket::leaveGroup(const IPAddress& groupAddress, const NetworkInterface& interfc)
{
if (groupAddress.af() == AF_INET)
{
struct ip_mreq mr;
std::memcpy(&mr.imr_multiaddr, groupAddress.addr(), groupAddress.length());
std::memcpy(&mr.imr_interface, interfc.firstAddress(IPAddress::IPv4).addr(), interfc.firstAddress(IPAddress::IPv4).length());
impl()->setRawOption(IPPROTO_IP, IP_DROP_MEMBERSHIP, &mr, sizeof(mr));
}
else
{
#if defined(POCO_HAVE_IPv6)
struct ipv6_mreq mr;
std::memcpy(&mr.ipv6mr_multiaddr, groupAddress.addr(), groupAddress.length());
mr.ipv6mr_interface = interfc.index();
impl()->setRawOption(IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, &mr, sizeof(mr));
#endif
}
}
} } // namespace Poco::Net
#endif // POCO_NET_HAS_INTERFACE
+309
View File
@@ -0,0 +1,309 @@
//
// MultipartReader.cpp
//
// Library: Net
// Package: Messages
// Module: MultipartReader
//
// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/MultipartReader.h"
#include "Poco/Net/MessageHeader.h"
#include "Poco/Net/NetException.h"
#include "Poco/Ascii.h"
using Poco::BufferedStreamBuf;
namespace Poco {
namespace Net {
//
// MultipartStreamBuf
//
MultipartStreamBuf::MultipartStreamBuf(std::istream& istr, const std::string& boundary):
BufferedStreamBuf(STREAM_BUFFER_SIZE, std::ios::in),
_istr(istr),
_boundary(boundary),
_lastPart(false)
{
poco_assert (!boundary.empty() && boundary.length() < STREAM_BUFFER_SIZE - 6);
}
MultipartStreamBuf::~MultipartStreamBuf()
{
}
int MultipartStreamBuf::readFromDevice(char* buffer, std::streamsize length)
{
poco_assert_dbg (length >= _boundary.length() + 6);
static const int eof = std::char_traits<char>::eof();
std::streambuf& buf = *_istr.rdbuf();
int n = 0;
int ch = buf.sbumpc();
if (ch == eof) return -1;
*buffer++ = (char) ch; ++n;
if (ch == '\n' || (ch == '\r' && buf.sgetc() == '\n'))
{
if (ch == '\r')
{
ch = buf.sbumpc(); // '\n'
*buffer++ = (char) ch; ++n;
}
ch = buf.sgetc();
if (ch == '\r' || ch == '\n') return n;
*buffer++ = (char) buf.sbumpc(); ++n;
if (ch == '-' && buf.sgetc() == '-')
{
ch = buf.sbumpc(); // '-'
*buffer++ = (char) ch; ++n;
std::string::const_iterator it = _boundary.begin();
std::string::const_iterator end = _boundary.end();
ch = buf.sbumpc();
*buffer++ = (char) ch; ++n;
while (it != end && ch == *it)
{
++it;
ch = buf.sbumpc();
*buffer++ = (char) ch; ++n;
}
if (it == end)
{
if (ch == '\n' || (ch == '\r' && buf.sgetc() == '\n'))
{
if (ch == '\r')
{
buf.sbumpc(); // '\n'
}
return 0;
}
else if (ch == '-' && buf.sgetc() == '-')
{
buf.sbumpc(); // '-'
_lastPart = true;
return 0;
}
}
}
}
ch = buf.sgetc();
while (ch != eof && ch != '\r' && ch != '\n' && n < length)
{
*buffer++ = (char) buf.sbumpc(); ++n;
ch = buf.sgetc();
}
return n;
}
bool MultipartStreamBuf::lastPart() const
{
return _lastPart;
}
//
// MultipartIOS
//
MultipartIOS::MultipartIOS(std::istream& istr, const std::string& boundary):
_buf(istr, boundary)
{
poco_ios_init(&_buf);
}
MultipartIOS::~MultipartIOS()
{
try
{
_buf.sync();
}
catch (...)
{
}
}
MultipartStreamBuf* MultipartIOS::rdbuf()
{
return &_buf;
}
bool MultipartIOS::lastPart() const
{
return _buf.lastPart();
}
//
// MultipartInputStream
//
MultipartInputStream::MultipartInputStream(std::istream& istr, const std::string& boundary):
MultipartIOS(istr, boundary),
std::istream(&_buf)
{
}
MultipartInputStream::~MultipartInputStream()
{
}
//
// MultipartReader
//
MultipartReader::MultipartReader(std::istream& istr):
_istr(istr),
_pMPI(0)
{
}
MultipartReader::MultipartReader(std::istream& istr, const std::string& boundary):
_istr(istr),
_boundary(boundary),
_pMPI(0)
{
}
MultipartReader::~MultipartReader()
{
delete _pMPI;
}
void MultipartReader::nextPart(MessageHeader& messageHeader)
{
if (!_pMPI)
{
if (_boundary.empty())
guessBoundary();
else
findFirstBoundary();
}
else if (_pMPI->lastPart())
{
throw MultipartException("No more parts available");
}
parseHeader(messageHeader);
delete _pMPI;
_pMPI = new MultipartInputStream(_istr, _boundary);
}
bool MultipartReader::hasNextPart()
{
return (!_pMPI || !_pMPI->lastPart()) && _istr.good();
}
std::istream& MultipartReader::stream() const
{
poco_check_ptr (_pMPI);
return *_pMPI;
}
const std::string& MultipartReader::boundary() const
{
return _boundary;
}
void MultipartReader::findFirstBoundary()
{
std::string expect("--");
expect.append(_boundary);
std::string line;
line.reserve(expect.length());
bool ok = true;
do
{
ok = readLine(line, expect.length());
}
while (ok && line != expect);
if (!ok) throw MultipartException("No boundary line found");
}
void MultipartReader::guessBoundary()
{
static const int eof = std::char_traits<char>::eof();
int ch = _istr.get();
while (Poco::Ascii::isSpace(ch))
ch = _istr.get();
if (ch == '-' && _istr.peek() == '-')
{
_istr.get();
ch = _istr.peek();
while (ch != eof && ch != '\r' && ch != '\n' && _boundary.size() < 128) // Note: should be no longer than 70 chars acc. to RFC 2046
{
_boundary += (char) _istr.get();
ch = _istr.peek();
}
if (ch != '\r' && ch != '\n')
throw MultipartException("Invalid boundary line found");
if (ch == '\r' || ch == '\n')
_istr.get();
if (_istr.peek() == '\n')
_istr.get();
}
else throw MultipartException("No boundary line found");
}
void MultipartReader::parseHeader(MessageHeader& messageHeader)
{
messageHeader.clear();
messageHeader.read(_istr);
int ch = _istr.get();
if (ch == '\r' && _istr.peek() == '\n') _istr.get();
}
bool MultipartReader::readLine(std::string& line, std::string::size_type n)
{
static const int eof = std::char_traits<char>::eof();
static const int maxLength = 1024;
line.clear();
int ch = _istr.peek();
int length = 0;
while (ch != eof && ch != '\r' && ch != '\n' && length < maxLength)
{
ch = (char) _istr.get();
if (line.length() < n) line += ch;
ch = _istr.peek();
length++;
}
if (ch != eof) _istr.get();
if (ch == '\r' && _istr.peek() == '\n') _istr.get();
return ch != eof && length < maxLength;
}
} } // namespace Poco::Net
+87
View File
@@ -0,0 +1,87 @@
//
// MultipartWriter.cpp
//
// Library: Net
// Package: Messages
// Module: MultipartWriter
//
// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/MultipartWriter.h"
#include "Poco/Net/MessageHeader.h"
#include "Poco/Random.h"
#include "Poco/NumberFormatter.h"
using Poco::Random;
using Poco::NumberFormatter;
namespace Poco {
namespace Net {
MultipartWriter::MultipartWriter(std::ostream& ostr):
_ostr(ostr),
_boundary(createBoundary()),
_firstPart(true)
{
}
MultipartWriter::MultipartWriter(std::ostream& ostr, const std::string& boundary):
_ostr(ostr),
_boundary(boundary),
_firstPart(true)
{
if (_boundary.empty())
_boundary = createBoundary();
}
MultipartWriter::~MultipartWriter()
{
}
void MultipartWriter::nextPart(const MessageHeader& header)
{
if (_firstPart)
_firstPart = false;
else
_ostr << "\r\n";
_ostr << "--" << _boundary << "\r\n";
header.write(_ostr);
_ostr << "\r\n";
}
void MultipartWriter::close()
{
_ostr << "\r\n--" << _boundary << "--\r\n";
}
const std::string& MultipartWriter::boundary() const
{
return _boundary;
}
std::string MultipartWriter::createBoundary()
{
std::string boundary("MIME_boundary_");
Random rnd;
rnd.seed();
NumberFormatter::appendHex(boundary, rnd.next(), 8);
NumberFormatter::appendHex(boundary, rnd.next(), 8);
return boundary;
}
} } // namespace Poco::Net
+380
View File
@@ -0,0 +1,380 @@
//
// NTLMCredentials.cpp
//
// Library: Net
// Package: NTLM
// Module: NTLMCredentials
//
// Copyright (c) 2019, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/NTLMCredentials.h"
#include "Poco/HMACEngine.h"
#include "Poco/MD4Engine.h"
#include "Poco/MD5Engine.h"
#include "Poco/DigestStream.h"
#include "Poco/StreamCopier.h"
#include "Poco/UTF8Encoding.h"
#include "Poco/UTF16Encoding.h"
#include "Poco/TextConverter.h"
#include "Poco/UTF8String.h"
#include "Poco/Random.h"
#include "Poco/Timestamp.h"
#include "Poco/MemoryStream.h"
#include "Poco/Base64Encoder.h"
#include "Poco/Base64Decoder.h"
#include <sstream>
#include <cstring>
namespace Poco {
namespace Net {
const std::string NTLMCredentials::NTLMSSP("NTLMSSP");
std::vector<unsigned char> NTLMCredentials::createNonce()
{
Poco::MD5Engine md5;
Poco::Random rnd;
rnd.seed();
Poco::UInt32 n = rnd.next();
md5.update(&n, sizeof(n));
Poco::Timestamp ts;
md5.update(&ts, sizeof(ts));
Poco::DigestEngine::Digest d = md5.digest();
d.resize(8);
return d;
}
Poco::UInt64 NTLMCredentials::createTimestamp()
{
const Poco::UInt64 EPOCH_DELTA_SECONDS = 11644473600; // seconds between January 1, 1970 and January 1, 1601
Poco::Timestamp now;
Poco::UInt64 ts = now.epochMicroseconds();
ts += EPOCH_DELTA_SECONDS*1000000; // since January 1, 1601
ts *= 10; // tenths of a microsecond
return ts;
}
std::vector<unsigned char> NTLMCredentials::createPasswordHash(const std::string& password)
{
Poco::UTF8Encoding utf8;
Poco::UTF16Encoding utf16(Poco::UTF16Encoding::LITTLE_ENDIAN_BYTE_ORDER);
Poco::TextConverter converter(utf8, utf16);
std::string utf16Password;
converter.convert(password, utf16Password);
Poco::MD4Engine md4;
md4.update(utf16Password);
return md4.digest();
}
std::vector<unsigned char> NTLMCredentials::createNTLMv2Hash(const std::string& username, const std::string& target, const std::string& password)
{
Poco::UTF8Encoding utf8;
Poco::UTF16Encoding utf16(Poco::UTF16Encoding::LITTLE_ENDIAN_BYTE_ORDER);
Poco::TextConverter converter(utf8, utf16);
std::vector<unsigned char> passwordHash = createPasswordHash(password);
std::string userDomain = Poco::UTF8::toUpper(username);
userDomain += target;
std::string utf16UserDomain;
converter.convert(userDomain, utf16UserDomain);
std::string passwordHashString(reinterpret_cast<const char*>(&passwordHash[0]), passwordHash.size());
Poco::HMACEngine<Poco::MD5Engine> hmac(passwordHashString);
hmac.update(utf16UserDomain);
return hmac.digest();
}
std::vector<unsigned char> NTLMCredentials::createLMv2Response(const std::vector<unsigned char>& ntlm2Hash, const std::vector<unsigned char>& challenge, const std::vector<unsigned char>& nonce)
{
poco_assert (challenge.size() == 8);
poco_assert (nonce.size() == 8);
std::vector<unsigned char> lm2Response;
std::string ntlm2HashString(reinterpret_cast<const char*>(&ntlm2Hash[0]), ntlm2Hash.size());
Poco::HMACEngine<Poco::MD5Engine> hmac2(ntlm2HashString);
hmac2.update(&challenge[0], challenge.size());
hmac2.update(&nonce[0], nonce.size());
lm2Response = hmac2.digest();
lm2Response.insert(lm2Response.end(), nonce.begin(), nonce.end());
return lm2Response;
}
std::vector<unsigned char> NTLMCredentials::createNTLMv2Response(const std::vector<unsigned char>& ntlm2Hash, const std::vector<unsigned char>& challenge, const std::vector<unsigned char>& nonce, const std::vector<unsigned char>& targetInfo, Poco::UInt64 timestamp)
{
poco_assert (challenge.size() == 8);
poco_assert (nonce.size() == 8);
std::vector<unsigned char> blob;
blob.resize(28 + targetInfo.size() + 4 + 16);
Poco::MemoryOutputStream blobStream(reinterpret_cast<char*>(&blob[16]), blob.size() - 16);
Poco::BinaryWriter writer(blobStream, Poco::BinaryWriter::LITTLE_ENDIAN_BYTE_ORDER);
writer << Poco::UInt32(0x0101);
writer << Poco::UInt32(0);
writer << timestamp;
writer.writeRaw(reinterpret_cast<const char*>(&nonce[0]), nonce.size());
writer << Poco::UInt32(0);
if (targetInfo.size() > 0)
{
writer.writeRaw(reinterpret_cast<const char*>(&targetInfo[0]), targetInfo.size());
}
writer << Poco::UInt32(0);
poco_assert_dbg (blobStream.charsWritten() == blob.size() - 16);
std::string ntlm2HashString(reinterpret_cast<const char*>(&ntlm2Hash[0]), ntlm2Hash.size());
Poco::HMACEngine<Poco::MD5Engine> hmac2(ntlm2HashString);
hmac2.update(&challenge[0], challenge.size());
hmac2.update(&blob[16], blob.size() - 16);
Poco::DigestEngine::Digest d = hmac2.digest();
poco_assert_dbg (d.size() == 16);
std::memcpy(&blob[0], &d[0], 16);
return blob;
}
std::vector<unsigned char> NTLMCredentials::formatNegotiateMessage(const NegotiateMessage& message)
{
Poco::UTF8Encoding utf8;
Poco::UTF16Encoding utf16(Poco::UTF16Encoding::LITTLE_ENDIAN_BYTE_ORDER);
Poco::TextConverter converter(utf8, utf16);
std::string utf16Domain;
converter.convert(message.domain, utf16Domain);
std::string utf16Workstation;
converter.convert(message.workstation, utf16Workstation);
std::size_t size = 8 // signature
+ 4 // type
+ 4 // flags
+ 8 + utf16Domain.size()
+ 8 + utf16Workstation.size();
Poco::UInt32 flags = message.flags | NTLM_FLAG_NEGOTIATE_UNICODE | NTLM_FLAG_REQUEST_TARGET | NTLM_FLAG_NEGOTIATE_NTLM | NTLM_FLAG_NEGOTIATE_NTLM2_KEY | NTLM_FLAG_NEGOTIATE_ALWAYS_SIGN;
if (!utf16Domain.empty()) flags |= NTLM_FLAG_DOMAIN_SUPPLIED;
if (!utf16Workstation.empty()) flags |= NTLM_FLAG_WORKST_SUPPLIED;
BufferDesc domainDesc(static_cast<Poco::UInt16>(utf16Domain.size()), 8 + 4 + 4 + 8);
BufferDesc workstDesc(static_cast<Poco::UInt16>(utf16Workstation.size()), domainDesc.offset + domainDesc.length);
std::vector<unsigned char> buffer(size);
Poco::MemoryOutputStream bufferStream(reinterpret_cast<char*>(&buffer[0]), buffer.size());
Poco::BinaryWriter writer(bufferStream, Poco::BinaryWriter::LITTLE_ENDIAN_BYTE_ORDER);
writer.writeRaw(NTLMSSP.c_str(), 8);
writer << Poco::UInt32(NTLM_MESSAGE_TYPE_NEGOTIATE);
writer << flags;
writeBufferDesc(writer, domainDesc);
writeBufferDesc(writer, workstDesc);
writer.writeRaw(utf16Domain);
writer.writeRaw(utf16Workstation);
return buffer;
}
bool NTLMCredentials::parseChallengeMessage(const unsigned char* buffer, std::size_t size, ChallengeMessage& message)
{
Poco::MemoryInputStream istr(reinterpret_cast<const char*>(buffer), size);
Poco::BinaryReader reader(istr, Poco::BinaryReader::LITTLE_ENDIAN_BYTE_ORDER);
std::string signature;
reader.readRaw(7, signature);
if (signature != NTLMSSP) return false;
Poco::UInt8 zero;
reader >> zero;
if (zero != 0) return false;
Poco::UInt32 type;
reader >> type;
if (type != NTLM_MESSAGE_TYPE_CHALLENGE) return false;
BufferDesc targetDesc;
readBufferDesc(reader, targetDesc);
if (targetDesc.offset + targetDesc.length > size) return false;
reader >> message.flags;
message.challenge.resize(8);
reader.readRaw(reinterpret_cast<char*>(&message.challenge[0]), 8);
if (message.flags & NTLM_FLAG_NEGOTIATE_TARGET)
{
Poco::UInt64 reserved;
reader >> reserved;
}
BufferDesc targetInfoDesc;
if (message.flags & NTLM_FLAG_NEGOTIATE_TARGET)
{
readBufferDesc(reader, targetInfoDesc);
if (targetInfoDesc.offset + targetInfoDesc.length > size) return false;
}
if (targetDesc.length > 0)
{
if (message.flags & NTLM_FLAG_NEGOTIATE_UNICODE)
{
Poco::UTF16Encoding utf16(Poco::UTF16Encoding::LITTLE_ENDIAN_BYTE_ORDER);
Poco::UTF8Encoding utf8;
Poco::TextConverter converter(utf16, utf8);
converter.convert(buffer + targetDesc.offset, targetDesc.length, message.target);
if (targetDesc.reserved == 0) message.target.resize(std::strlen(message.target.c_str()));
}
else
{
message.target.assign(buffer + targetDesc.offset, buffer + targetDesc.offset + targetDesc.length);
}
}
if (targetInfoDesc.length > 0)
{
message.targetInfo.assign(buffer + targetInfoDesc.offset, buffer + targetInfoDesc.offset + targetInfoDesc.length);
}
return true;
}
std::vector<unsigned char> NTLMCredentials::formatAuthenticateMessage(const AuthenticateMessage& message)
{
Poco::UTF8Encoding utf8;
Poco::UTF16Encoding utf16(Poco::UTF16Encoding::LITTLE_ENDIAN_BYTE_ORDER);
Poco::TextConverter converter(utf8, utf16);
std::string utf16Target;
converter.convert(message.target, utf16Target);
std::string utf16Username;
converter.convert(message.username, utf16Username);
std::string utf16Workstation;
converter.convert(message.workstation, utf16Workstation);
std::size_t size = 8 // signature
+ 4 // type
+ 8 + message.lmResponse.size()
+ 8 + message.ntlmResponse.size()
+ 8 + utf16Target.size()
+ 8 + utf16Username.size()
+ 8 + utf16Workstation.size()
+ 8 // session key
+ 4; // flags
Poco::UInt32 flags = message.flags | NTLM_FLAG_NEGOTIATE_UNICODE;
BufferDesc lmDesc(static_cast<Poco::UInt16>(message.lmResponse.size()), 64);
BufferDesc ntlmDesc(static_cast<Poco::UInt16>(message.ntlmResponse.size()), lmDesc.offset + lmDesc.length);
BufferDesc targetDesc(static_cast<Poco::UInt16>(utf16Target.size()), ntlmDesc.offset + ntlmDesc.length);
BufferDesc usernameDesc(static_cast<Poco::UInt16>(utf16Username.size()), targetDesc.offset + targetDesc.length);
BufferDesc workstDesc(static_cast<Poco::UInt16>(utf16Workstation.size()), usernameDesc.offset + usernameDesc.length);
BufferDesc sessionKeyDesc(0, workstDesc.offset + workstDesc.length);
std::vector<unsigned char> buffer(size);
Poco::MemoryOutputStream bufferStream(reinterpret_cast<char*>(&buffer[0]), buffer.size());
Poco::BinaryWriter writer(bufferStream, Poco::BinaryWriter::LITTLE_ENDIAN_BYTE_ORDER);
writer.writeRaw(NTLMSSP.c_str(), 8);
writer << Poco::UInt32(NTLM_MESSAGE_TYPE_AUTHENTICATE);
writeBufferDesc(writer, lmDesc);
writeBufferDesc(writer, ntlmDesc);
writeBufferDesc(writer, targetDesc);
writeBufferDesc(writer, usernameDesc);
writeBufferDesc(writer, workstDesc);
writeBufferDesc(writer, sessionKeyDesc);
writer << flags;
writer.writeRaw(reinterpret_cast<const char*>(&message.lmResponse[0]), message.lmResponse.size());
writer.writeRaw(reinterpret_cast<const char*>(&message.ntlmResponse[0]), message.ntlmResponse.size());
writer.writeRaw(utf16Target);
writer.writeRaw(utf16Username);
writer.writeRaw(utf16Workstation);
return buffer;
}
void NTLMCredentials::readBufferDesc(Poco::BinaryReader& reader, BufferDesc& desc)
{
reader >> desc.length >> desc.reserved >> desc.offset;
}
void NTLMCredentials::writeBufferDesc(Poco::BinaryWriter& writer, const BufferDesc& desc)
{
writer << desc.length << desc.reserved << desc.offset;
}
void NTLMCredentials::splitUsername(const std::string& usernameAndDomain, std::string& username, std::string& domain)
{
std::string::size_type pos = usernameAndDomain.find('\\');
if (pos != std::string::npos)
{
domain.assign(usernameAndDomain, 0, pos);
username.assign(usernameAndDomain, pos + 1, std::string::npos);
return;
}
else
{
pos = usernameAndDomain.find('@');
if (pos != std::string::npos)
{
username.assign(usernameAndDomain, 0, pos);
domain.assign(usernameAndDomain, pos + 1, std::string::npos);
return;
}
}
username = usernameAndDomain;
}
std::string NTLMCredentials::toBase64(const std::vector<unsigned char>& buffer)
{
std::ostringstream ostr;
Poco::Base64Encoder base64(ostr);
base64.rdbuf()->setLineLength(0);
base64.write(reinterpret_cast<const char*>(&buffer[0]), buffer.size());
base64.close();
return ostr.str();
}
std::vector<unsigned char> NTLMCredentials::fromBase64(const std::string& base64)
{
Poco::MemoryInputStream istr(base64.data(), base64.size());
Poco::Base64Decoder debase64(istr);
std::vector<unsigned char> buffer(base64.size());
debase64.read(reinterpret_cast<char*>(&buffer[0]), buffer.size());
buffer.resize(static_cast<std::size_t>(debase64.gcount()));
return buffer;
}
} } // namespace Poco::Net
+95
View File
@@ -0,0 +1,95 @@
//
// NTPClient.cpp
//
// Library: Net
// Package: NTP
// Module: NTPClient
//
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/SocketAddress.h"
#include "Poco/Net/NTPClient.h"
#include "Poco/Net/NTPPacket.h"
#include "Poco/Net/DatagramSocket.h"
#include "Poco/Net/NetException.h"
using Poco::TimeoutException;
namespace Poco {
namespace Net {
NTPClient::NTPClient(IPAddress::Family family, int timeout):
_family(family), _timeout(timeout)
{
}
NTPClient::~NTPClient()
{
}
int NTPClient::request(const std::string& address) const
{
SocketAddress addr(address, 123);
return request(addr);
}
int NTPClient::request(SocketAddress& address) const
{
SocketAddress sa;
DatagramSocket ntpSocket(_family);
ntpSocket.setReceiveTimeout(_timeout);
ntpSocket.bind(sa);
SocketAddress returnAddress;
NTPEventArgs eventArgs(address);
NTPPacket packet;
Poco::UInt8 p[1024];
packet.packet(&p[0]);
ntpSocket.sendTo(p, 48, address);
int received = 0;
Timestamp start;
while (true)
{
try
{
int n = ntpSocket.receiveFrom(p, sizeof(p) - 1, sa);
if (sa != address) // reply mixup, try until timeout ...
{
if ((Timestamp() - start) < _timeout) continue;
break;
}
if (n < 48) // NTP packet must have at least 48 bytes
throw Poco::Net::NTPException("Invalid response received");
packet.setPacket(p);
eventArgs.setPacket(packet);
++received;
response.notify(this, eventArgs);
break;
}
catch (Poco::TimeoutException &)
{
break;
}
}
return received;
}
} } // namespace Poco::Net
+71
View File
@@ -0,0 +1,71 @@
//
// NTPEventArgs.cpp
//
// Library: Net
// Package: NTP
// Module: NTPEventArgs
//
// Implementation of NTPEventArgs
//
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/NTPEventArgs.h"
#include "Poco/Net/SocketAddress.h"
#include "Poco/Net/DNS.h"
#include "Poco/Exception.h"
#include "Poco/Net/NetException.h"
using Poco::IOException;
using Poco::InvalidArgumentException;
namespace Poco {
namespace Net {
NTPEventArgs::NTPEventArgs(const SocketAddress& address):
_address(address), _packet()
{
}
NTPEventArgs::~NTPEventArgs()
{
}
std::string NTPEventArgs::hostName() const
{
try
{
return DNS::resolve(_address.host().toString()).name();
}
catch (HostNotFoundException&)
{
}
catch (NoAddressFoundException&)
{
}
catch (DNSException&)
{
}
catch (IOException&)
{
}
return _address.host().toString();
}
std::string NTPEventArgs::hostAddress() const
{
return _address.host().toString();
}
} } // namespace Poco::Net
+158
View File
@@ -0,0 +1,158 @@
//
// NTPPacket.cpp
//
// Library: Net
// Package: NTP
// Module: NTPPacket
//
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/NTPPacket.h"
#include "Poco/Net/NetException.h"
#include "Poco/Timestamp.h"
#include "Poco/ByteOrder.h"
namespace Poco {
namespace Net {
#if !defined(POCO_COMPILER_SUN)
#pragma pack(push, 1)
#else
#pragma pack(1)
#endif
struct NTPPacketData
{
Poco::Int8 mode:3;
Poco::Int8 vn:3;
Poco::Int8 li:2;
Poco::Int8 stratum;
Poco::Int8 pool;
Poco::Int8 prec;
Poco::Int32 rootdelay;
Poco::Int32 rootdisp;
Poco::Int32 refid;
Poco::Int64 rts;
Poco::Int64 ots;
Poco::Int64 vts;
Poco::Int64 tts;
};
#if !defined(POCO_COMPILER_SUN)
#pragma pack(pop)
#else
#pragma pack()
#endif
NTPPacket::NTPPacket() :
// the next 3 fields must be in reverse order from spec
_leapIndicator(3),
_version(4),
_mode(3),
_stratum(0),
_pool(6),
_precision(-18),
_rootDelay(0),
_rootDispersion(0),
_referenceId(0),
_referenceTimestamp(0),
_receiveTimestamp(0),
_transmitTimestamp(0)
{
Poco::Timestamp ts;
_originateTimestamp = ts.utcTime() - 2874597888;
}
NTPPacket::NTPPacket(Poco::UInt8 *packet)
{
setPacket(packet);
}
NTPPacket::~NTPPacket()
{
}
void NTPPacket::packet(Poco::UInt8 *packet) const
{
NTPPacketData *p = (NTPPacketData*)packet;
p->li = _leapIndicator;
p->vn = _version;
p->mode = _mode;
p->stratum = _stratum;
p->pool = _pool;
p->prec = _precision;
p->rootdelay = Poco::ByteOrder::toNetwork(_rootDelay);
p->rootdisp = Poco::ByteOrder::toNetwork(_rootDispersion);
p->refid = Poco::ByteOrder::toNetwork(_referenceId);
p->rts = Poco::ByteOrder::toNetwork(_referenceTimestamp);
p->ots = Poco::ByteOrder::toNetwork(_originateTimestamp);
p->vts = Poco::ByteOrder::toNetwork(_receiveTimestamp);
p->tts = Poco::ByteOrder::toNetwork(_transmitTimestamp);
}
void NTPPacket::setPacket(Poco::UInt8 *packet)
{
NTPPacketData *p = (NTPPacketData*)packet;
_leapIndicator = p->li;
_version = p->vn;
_mode = p->mode;
_stratum = p->stratum;
_pool = p->pool;
_precision = p->prec;
_rootDelay = Poco::ByteOrder::fromNetwork(p->rootdelay);
_rootDispersion = Poco::ByteOrder::fromNetwork(p->rootdisp);
_referenceId = Poco::ByteOrder::fromNetwork(p->refid);
_referenceTimestamp = Poco::ByteOrder::fromNetwork(p->rts);
_originateTimestamp = Poco::ByteOrder::fromNetwork(p->ots);
_receiveTimestamp = Poco::ByteOrder::fromNetwork(p->vts);
_transmitTimestamp = Poco::ByteOrder::fromNetwork(p->tts);
}
Poco::Timestamp NTPPacket::referenceTime() const
{
return convertTime(_referenceTimestamp);
}
Poco::Timestamp NTPPacket::originateTime() const
{
return convertTime(_originateTimestamp);
}
Poco::Timestamp NTPPacket::receiveTime() const
{
return convertTime(_receiveTimestamp);
}
Poco::Timestamp NTPPacket::transmitTime() const
{
return convertTime(_transmitTimestamp);
}
Poco::Timestamp NTPPacket::convertTime(Poco::Int64 tm) const
{
const unsigned long seventyYears = 2208988800UL;
Poco::UInt32 secsSince1900 = UInt32(Poco::ByteOrder::toLittleEndian(tm) >> 32);
unsigned long epoch = secsSince1900 - seventyYears;
return Poco::Timestamp::fromEpochTime(epoch);
}
} } // namespace Poco::Net
+166
View File
@@ -0,0 +1,166 @@
//
// NameValueCollection.cpp
//
// Library: Net
// Package: Messages
// Module: NameValueCollection
//
// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/NameValueCollection.h"
#include "Poco/Exception.h"
#include <algorithm>
using Poco::NotFoundException;
namespace Poco {
namespace Net {
NameValueCollection::NameValueCollection()
{
}
NameValueCollection::NameValueCollection(const NameValueCollection& nvc):
_map(nvc._map)
{
}
NameValueCollection::NameValueCollection(NameValueCollection&& nvc) noexcept:
_map(std::move(nvc._map))
{
}
NameValueCollection::~NameValueCollection()
{
}
NameValueCollection& NameValueCollection::operator = (const NameValueCollection& nvc)
{
NameValueCollection tmp(nvc);
swap(tmp);
return *this;
}
NameValueCollection& NameValueCollection::operator = (NameValueCollection&& nvc) noexcept
{
_map = std::move(nvc._map);
return *this;
}
void NameValueCollection::swap(NameValueCollection& nvc)
{
std::swap(_map, nvc._map);
}
const std::string& NameValueCollection::operator [] (const std::string& name) const
{
ConstIterator it = _map.find(name);
if (it != _map.end())
return it->second;
else
throw NotFoundException(name);
}
void NameValueCollection::set(const std::string& name, const std::string& value)
{
Iterator it = _map.find(name);
if (it != _map.end())
it->second = value;
else
_map.insert(HeaderMap::ValueType(name, value));
}
void NameValueCollection::add(const std::string& name, const std::string& value)
{
_map.insert(HeaderMap::ValueType(name, value));
}
const std::string& NameValueCollection::get(const std::string& name) const
{
ConstIterator it = _map.find(name);
if (it != _map.end())
return it->second;
else
throw NotFoundException(name);
}
const std::string& NameValueCollection::get(const std::string& name, const std::string& defaultValue) const
{
ConstIterator it = _map.find(name);
if (it != _map.end())
return it->second;
else
return defaultValue;
}
bool NameValueCollection::has(const std::string& name) const
{
return _map.find(name) != _map.end();
}
NameValueCollection::ConstIterator NameValueCollection::find(const std::string& name) const
{
return _map.find(name);
}
NameValueCollection::ConstIterator NameValueCollection::begin() const
{
return _map.begin();
}
NameValueCollection::ConstIterator NameValueCollection::end() const
{
return _map.end();
}
bool NameValueCollection::empty() const
{
return _map.empty();
}
std::size_t NameValueCollection::size() const
{
return _map.size();
}
void NameValueCollection::erase(const std::string& name)
{
_map.erase(name);
}
void NameValueCollection::clear()
{
_map.clear();
}
} } // namespace Poco::Net
+96
View File
@@ -0,0 +1,96 @@
//
// Net.cpp
//
// Library: Net
// Package: NetCore
// Module: NetCore
//
// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/Net.h"
#include "Poco/Net/SocketDefs.h"
#include "Poco/Net/NetException.h"
namespace Poco {
namespace Net {
void Net_API initializeNetwork()
{
#if defined(POCO_OS_FAMILY_WINDOWS)
WORD version = MAKEWORD(2, 2);
WSADATA data;
if (WSAStartup(version, &data) != 0)
throw NetException("Failed to initialize network subsystem");
#endif
}
void Net_API uninitializeNetwork()
{
#if defined(POCO_OS_FAMILY_WINDOWS)
WSACleanup();
#endif
}
std::string htmlize(const std::string& str)
{
std::string::const_iterator it(str.begin());
std::string::const_iterator end(str.end());
std::string html;
for (; it != end; ++it)
{
switch (*it)
{
case '<': html += "&lt;"; break;
case '>': html += "&gt;"; break;
case '"': html += "&quot;"; break;
case '&': html += "&amp;"; break;
default: html += *it; break;
}
}
return html;
}
} } // namespace Poco::Net
#if defined(POCO_OS_FAMILY_WINDOWS) && !defined(POCO_NO_AUTOMATIC_LIB_INIT)
struct NetworkInitializer
/// Network initializer for windows statically
/// linked library.
{
NetworkInitializer()
/// Calls Poco::Net::initializeNetwork();
{
Poco::Net::initializeNetwork();
}
~NetworkInitializer()
/// Calls Poco::Net::uninitializeNetwork();
{
try
{
Poco::Net::uninitializeNetwork();
}
catch (...)
{
poco_unexpected();
}
}
};
const NetworkInitializer pocoNetworkInitializer;
#endif
+55
View File
@@ -0,0 +1,55 @@
//
// NetException.cpp
//
// Library: Net
// Package: NetCore
// Module: NetException
//
// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/NetException.h"
#include <typeinfo>
using Poco::IOException;
namespace Poco {
namespace Net {
POCO_IMPLEMENT_EXCEPTION(NetException, IOException, "Net Exception")
POCO_IMPLEMENT_EXCEPTION(InvalidAddressException, NetException, "Invalid address")
POCO_IMPLEMENT_EXCEPTION(InvalidSocketException, NetException, "Invalid socket")
POCO_IMPLEMENT_EXCEPTION(ServiceNotFoundException, NetException, "Service not found")
POCO_IMPLEMENT_EXCEPTION(ConnectionAbortedException, NetException, "Software caused connection abort")
POCO_IMPLEMENT_EXCEPTION(ConnectionResetException, NetException, "Connection reset by peer")
POCO_IMPLEMENT_EXCEPTION(ConnectionRefusedException, NetException, "Connection refused")
POCO_IMPLEMENT_EXCEPTION(DNSException, NetException, "DNS error")
POCO_IMPLEMENT_EXCEPTION(HostNotFoundException, DNSException, "Host not found")
POCO_IMPLEMENT_EXCEPTION(NoAddressFoundException, DNSException, "No address found")
POCO_IMPLEMENT_EXCEPTION(InterfaceNotFoundException, NetException, "Interface not found")
POCO_IMPLEMENT_EXCEPTION(NoMessageException, NetException, "No message received")
POCO_IMPLEMENT_EXCEPTION(MessageException, NetException, "Malformed message")
POCO_IMPLEMENT_EXCEPTION(MultipartException, MessageException, "Malformed multipart message")
POCO_IMPLEMENT_EXCEPTION(HTTPException, NetException, "HTTP Exception")
POCO_IMPLEMENT_EXCEPTION(NotAuthenticatedException, HTTPException, "No authentication information found")
POCO_IMPLEMENT_EXCEPTION(UnsupportedRedirectException, HTTPException, "Unsupported HTTP redirect (protocol change)")
POCO_IMPLEMENT_EXCEPTION(FTPException, NetException, "FTP Exception")
POCO_IMPLEMENT_EXCEPTION(SMTPException, NetException, "SMTP Exception")
POCO_IMPLEMENT_EXCEPTION(POP3Exception, NetException, "POP3 Exception")
POCO_IMPLEMENT_EXCEPTION(ICMPException, NetException, "ICMP Exception")
POCO_IMPLEMENT_EXCEPTION(ICMPFragmentationException, NetException, "ICMP Fragmentation needed")
POCO_IMPLEMENT_EXCEPTION(NTPException, NetException, "NTP Exception")
POCO_IMPLEMENT_EXCEPTION(HTMLFormException, NetException, "HTML Form Exception")
POCO_IMPLEMENT_EXCEPTION(WebSocketException, NetException, "WebSocket Exception")
POCO_IMPLEMENT_EXCEPTION(UnsupportedFamilyException, NetException, "Unknown or unsupported socket family")
POCO_IMPLEMENT_EXCEPTION(AddressFamilyMismatchException, NetException, "Address family mismatch")
} } // namespace Poco::Net
File diff suppressed because it is too large Load Diff
+46
View File
@@ -0,0 +1,46 @@
//
// NullPartHandler.cpp
//
// Library: Net
// Package: Messages
// Module: NullPartHandler
//
// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/NullPartHandler.h"
#include "Poco/Net/MessageHeader.h"
#include "Poco/NullStream.h"
#include "Poco/StreamCopier.h"
using Poco::NullOutputStream;
using Poco::StreamCopier;
namespace Poco {
namespace Net {
NullPartHandler::NullPartHandler()
{
}
NullPartHandler::~NullPartHandler()
{
}
void NullPartHandler::handlePart(const MessageHeader& header, std::istream& stream)
{
NullOutputStream ostr;
StreamCopier::copyStream(stream, ostr);
}
} } // namespace Poco::Net
+365
View File
@@ -0,0 +1,365 @@
//
// OAuth10Credentials.cpp
//
// Library: Net
// Package: OAuth
// Module: OAuth10Credentials
//
// Copyright (c) 2014, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/OAuth10Credentials.h"
#include "Poco/Net/HTTPRequest.h"
#include "Poco/Net/HTMLForm.h"
#include "Poco/Net/NetException.h"
#include "Poco/Net/HTTPAuthenticationParams.h"
#include "Poco/SHA1Engine.h"
#include "Poco/HMACEngine.h"
#include "Poco/Base64Encoder.h"
#include "Poco/RandomStream.h"
#include "Poco/Timestamp.h"
#include "Poco/NumberParser.h"
#include "Poco/NumberFormatter.h"
#include "Poco/Format.h"
#include "Poco/String.h"
#include <map>
#include <sstream>
namespace Poco {
namespace Net {
const std::string OAuth10Credentials::SCHEME = "OAuth";
OAuth10Credentials::OAuth10Credentials()
{
}
OAuth10Credentials::OAuth10Credentials(const std::string& consumerKey, const std::string& consumerSecret):
_consumerKey(consumerKey),
_consumerSecret(consumerSecret)
{
}
OAuth10Credentials::OAuth10Credentials(const std::string& consumerKey, const std::string& consumerSecret, const std::string& token, const std::string& tokenSecret):
_consumerKey(consumerKey),
_consumerSecret(consumerSecret),
_token(token),
_tokenSecret(tokenSecret)
{
}
OAuth10Credentials::OAuth10Credentials(const Poco::Net::HTTPRequest& request)
{
if (request.hasCredentials())
{
std::string authScheme;
std::string authParams;
request.getCredentials(authScheme, authParams);
if (icompare(authScheme, SCHEME) == 0)
{
HTTPAuthenticationParams params(authParams);
std::string consumerKey = params.get("oauth_consumer_key", "");
URI::decode(consumerKey, _consumerKey);
std::string token = params.get("oauth_token", "");
URI::decode(token, _token);
std::string callback = params.get("oauth_callback", "");
URI::decode(callback, _callback);
}
else throw NotAuthenticatedException("No OAuth credentials in Authorization header", authScheme);
}
else throw NotAuthenticatedException("No Authorization header found");
}
OAuth10Credentials::~OAuth10Credentials()
{
}
void OAuth10Credentials::setConsumerKey(const std::string& consumerKey)
{
_consumerKey = consumerKey;
}
void OAuth10Credentials::setConsumerSecret(const std::string& consumerSecret)
{
_consumerSecret = consumerSecret;
}
void OAuth10Credentials::setToken(const std::string& token)
{
_token = token;
}
void OAuth10Credentials::setTokenSecret(const std::string& tokenSecret)
{
_tokenSecret = tokenSecret;
}
void OAuth10Credentials::setRealm(const std::string& realm)
{
_realm = realm;
}
void OAuth10Credentials::setCallback(const std::string& callback)
{
_callback = callback;
}
void OAuth10Credentials::authenticate(HTTPRequest& request, const Poco::URI& uri, SignatureMethod method)
{
HTMLForm emptyParams;
authenticate(request, uri, emptyParams, method);
}
void OAuth10Credentials::authenticate(HTTPRequest& request, const Poco::URI& uri, const Poco::Net::HTMLForm& params, SignatureMethod method)
{
if (method == SIGN_PLAINTEXT)
{
signPlaintext(request);
}
else
{
URI uriWithoutQuery(uri);
uriWithoutQuery.setQuery("");
uriWithoutQuery.setFragment("");
signHMACSHA1(request, uriWithoutQuery.toString(), params);
}
}
bool OAuth10Credentials::verify(const HTTPRequest& request, const Poco::URI& uri)
{
HTMLForm params;
return verify(request, uri, params);
}
bool OAuth10Credentials::verify(const HTTPRequest& request, const Poco::URI& uri, const Poco::Net::HTMLForm& params)
{
if (request.hasCredentials())
{
std::string authScheme;
std::string authParams;
request.getCredentials(authScheme, authParams);
if (icompare(authScheme, SCHEME) == 0)
{
HTTPAuthenticationParams oauthParams(authParams);
std::string version = oauthParams.get("oauth_version", "1.0");
if (version != "1.0") throw NotAuthenticatedException("Unsupported OAuth version", version);
_consumerKey.clear();
std::string consumerKey = oauthParams.get("oauth_consumer_key", "");
URI::decode(consumerKey, _consumerKey);
_token.clear();
std::string token = oauthParams.get("oauth_token", "");
URI::decode(token, _token);
_callback.clear();
std::string callback = oauthParams.get("oauth_callback", "");
URI::decode(callback, _callback);
std::string nonceEnc = oauthParams.get("oauth_nonce", "");
std::string nonce;
URI::decode(nonceEnc, nonce);
std::string timestamp = oauthParams.get("oauth_timestamp", "");
std::string method = oauthParams.get("oauth_signature_method", "");
std::string signatureEnc = oauthParams.get("oauth_signature", "");
std::string signature;
URI::decode(signatureEnc, signature);
std::string refSignature;
if (icompare(method, "PLAINTEXT") == 0)
{
refSignature = percentEncode(_consumerSecret);
refSignature += '&';
refSignature += percentEncode(_tokenSecret);
}
else if (icompare(method, "HMAC-SHA1") == 0)
{
URI uriWithoutQuery(uri);
uriWithoutQuery.setQuery("");
uriWithoutQuery.setFragment("");
refSignature = createSignature(request, uriWithoutQuery.toString(), params, nonce, timestamp);
}
else throw NotAuthenticatedException("Unsupported OAuth signature method", method);
return refSignature == signature;
}
else throw NotAuthenticatedException("No OAuth credentials found in Authorization header");
}
else throw NotAuthenticatedException("No Authorization header found");
}
void OAuth10Credentials::nonceAndTimestampForTesting(const std::string& nonce, const std::string& timestamp)
{
_nonce = nonce;
_timestamp = timestamp;
}
void OAuth10Credentials::signPlaintext(Poco::Net::HTTPRequest& request) const
{
std::string signature(percentEncode(_consumerSecret));
signature += '&';
signature += percentEncode(_tokenSecret);
std::string authorization(SCHEME);
if (!_realm.empty())
{
Poco::format(authorization, " realm=\"%s\",", _realm);
}
Poco::format(authorization, " oauth_consumer_key=\"%s\"", percentEncode(_consumerKey));
Poco::format(authorization, ", oauth_signature=\"%s\"", percentEncode(signature));
authorization += ", oauth_signature_method=\"PLAINTEXT\"";
if (!_token.empty())
{
Poco::format(authorization, ", oauth_token=\"%s\"", percentEncode(_token));
}
if (!_callback.empty())
{
Poco::format(authorization, ", oauth_callback=\"%s\"", percentEncode(_callback));
}
authorization += ", oauth_version=\"1.0\"";
request.set(HTTPRequest::AUTHORIZATION, authorization);
}
void OAuth10Credentials::signHMACSHA1(Poco::Net::HTTPRequest& request, const std::string& uri, const Poco::Net::HTMLForm& params) const
{
std::string nonce(_nonce);
if (nonce.empty())
{
nonce = createNonce();
}
std::string timestamp(_timestamp);
if (timestamp.empty())
{
timestamp = Poco::NumberFormatter::format(Poco::Timestamp().epochTime());
}
std::string signature(createSignature(request, uri, params, nonce, timestamp));
std::string authorization(SCHEME);
if (!_realm.empty())
{
Poco::format(authorization, " realm=\"%s\",", _realm);
}
Poco::format(authorization, " oauth_consumer_key=\"%s\"", percentEncode(_consumerKey));
Poco::format(authorization, ", oauth_nonce=\"%s\"", percentEncode(nonce));
Poco::format(authorization, ", oauth_signature=\"%s\"", percentEncode(signature));
authorization += ", oauth_signature_method=\"HMAC-SHA1\"";
Poco::format(authorization, ", oauth_timestamp=\"%s\"", timestamp);
if (!_token.empty())
{
Poco::format(authorization, ", oauth_token=\"%s\"", percentEncode(_token));
}
if (!_callback.empty())
{
Poco::format(authorization, ", oauth_callback=\"%s\"", percentEncode(_callback));
}
authorization += ", oauth_version=\"1.0\"";
request.set(HTTPRequest::AUTHORIZATION, authorization);
}
std::string OAuth10Credentials::createNonce() const
{
std::ostringstream base64Nonce;
Poco::Base64Encoder base64Encoder(base64Nonce);
Poco::RandomInputStream randomStream;
for (int i = 0; i < 32; i++)
{
base64Encoder.put(randomStream.get());
}
base64Encoder.close();
std::string nonce = base64Nonce.str();
return Poco::translate(nonce, "+/=", "");
}
std::string OAuth10Credentials::createSignature(const Poco::Net::HTTPRequest& request, const std::string& uri, const Poco::Net::HTMLForm& params, const std::string& nonce, const std::string& timestamp) const
{
std::map<std::string, std::string> paramsMap;
paramsMap["oauth_version"] = "1.0";
paramsMap["oauth_consumer_key"] = percentEncode(_consumerKey);
paramsMap["oauth_nonce"] = percentEncode(nonce);
paramsMap["oauth_signature_method"] = "HMAC-SHA1";
paramsMap["oauth_timestamp"] = timestamp;
if (!_token.empty())
{
paramsMap["oauth_token"] = percentEncode(_token);
}
if (!_callback.empty())
{
paramsMap["oauth_callback"] = percentEncode(_callback);
}
for (const auto& p: params)
{
paramsMap[percentEncode(p.first)] = percentEncode(p.second);
}
std::string paramsString;
for (auto it = paramsMap.begin(); it != paramsMap.end(); ++it)
{
if (it != paramsMap.begin()) paramsString += '&';
paramsString += it->first;
paramsString += "=";
paramsString += it->second;
}
std::string signatureBase = request.getMethod();
signatureBase += '&';
signatureBase += percentEncode(uri);
signatureBase += '&';
signatureBase += percentEncode(paramsString);
std::string signingKey;
signingKey += percentEncode(_consumerSecret);
signingKey += '&';
signingKey += percentEncode(_tokenSecret);
Poco::HMACEngine<Poco::SHA1Engine> hmacEngine(signingKey);
hmacEngine.update(signatureBase);
Poco::DigestEngine::Digest digest = hmacEngine.digest();
std::ostringstream digestBase64;
Poco::Base64Encoder base64Encoder(digestBase64);
base64Encoder.write(reinterpret_cast<char*>(&digest[0]), digest.size());
base64Encoder.close();
return digestBase64.str();
}
std::string OAuth10Credentials::percentEncode(const std::string& str)
{
std::string encoded;
Poco::URI::encode(str, "!?#/'\",;:$&()[]*+=@", encoded);
return encoded;
}
} } // namespace Poco::Net
+105
View File
@@ -0,0 +1,105 @@
//
// OAuth20Credentials.cpp
//
// Library: Net
// Package: OAuth
// Module: OAuth20Credentials
//
// Copyright (c) 2014, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/OAuth20Credentials.h"
#include "Poco/Net/HTTPRequest.h"
#include "Poco/Net/NetException.h"
#include "Poco/String.h"
namespace Poco {
namespace Net {
const std::string OAuth20Credentials::SCHEME = "Bearer";
OAuth20Credentials::OAuth20Credentials():
_scheme(SCHEME)
{
}
OAuth20Credentials::OAuth20Credentials(const std::string& bearerToken):
_bearerToken(bearerToken),
_scheme(SCHEME)
{
}
OAuth20Credentials::OAuth20Credentials(const std::string& bearerToken, const std::string& scheme):
_bearerToken(bearerToken),
_scheme(scheme)
{
}
OAuth20Credentials::OAuth20Credentials(const HTTPRequest& request):
_scheme(SCHEME)
{
extractBearerToken(request);
}
OAuth20Credentials::OAuth20Credentials(const HTTPRequest& request, const std::string& scheme):
_scheme(scheme)
{
extractBearerToken(request);
}
OAuth20Credentials::~OAuth20Credentials()
{
}
void OAuth20Credentials::setBearerToken(const std::string& bearerToken)
{
_bearerToken = bearerToken;
}
void OAuth20Credentials::setScheme(const std::string& scheme)
{
_scheme = scheme;
}
void OAuth20Credentials::authenticate(HTTPRequest& request)
{
std::string auth(_scheme);
auth += ' ';
auth += _bearerToken;
request.set(HTTPRequest::AUTHORIZATION, auth);
}
void OAuth20Credentials::extractBearerToken(const HTTPRequest& request)
{
if (request.hasCredentials())
{
std::string authScheme;
std::string authInfo;
request.getCredentials(authScheme, authInfo);
if (icompare(authScheme, _scheme) == 0)
{
_bearerToken = authInfo;
}
else throw NotAuthenticatedException("No bearer token in Authorization header", authScheme);
}
else throw NotAuthenticatedException("No Authorization header found");
}
} } // namespace Poco::Net
+280
View File
@@ -0,0 +1,280 @@
//
// POP3ClientSession.cpp
//
// Library: Net
// Package: Mail
// Module: POP3ClientSession
//
// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/POP3ClientSession.h"
#include "Poco/Net/MailMessage.h"
#include "Poco/Net/MailStream.h"
#include "Poco/Net/SocketAddress.h"
#include "Poco/Net/NetException.h"
#include "Poco/StreamCopier.h"
#include "Poco/NumberFormatter.h"
#include "Poco/UnbufferedStreamBuf.h"
#include "Poco/Ascii.h"
#include <istream>
using Poco::NumberFormatter;
using Poco::StreamCopier;
namespace Poco {
namespace Net {
class DialogStreamBuf: public Poco::UnbufferedStreamBuf
{
public:
DialogStreamBuf(DialogSocket& socket):
_socket(socket)
{
}
~DialogStreamBuf()
{
}
private:
int readFromDevice()
{
return _socket.get();
}
DialogSocket& _socket;
};
class DialogIOS: public virtual std::ios
{
public:
DialogIOS(DialogSocket& socket):
_buf(socket)
{
poco_ios_init(&_buf);
}
~DialogIOS()
{
}
DialogStreamBuf* rdbuf()
{
return &_buf;
}
protected:
DialogStreamBuf _buf;
};
class DialogInputStream: public DialogIOS, public std::istream
{
public:
DialogInputStream(DialogSocket& socket):
DialogIOS(socket),
std::istream(&_buf)
{
}
~DialogInputStream()
{
}
};
POP3ClientSession::POP3ClientSession(const StreamSocket& socket):
_socket(socket),
_isOpen(true)
{
}
POP3ClientSession::POP3ClientSession(const std::string& host, Poco::UInt16 port):
_socket(SocketAddress(host, port)),
_isOpen(true)
{
}
POP3ClientSession::~POP3ClientSession()
{
try
{
close();
}
catch (...)
{
}
}
void POP3ClientSession::setTimeout(const Poco::Timespan& timeout)
{
_socket.setReceiveTimeout(timeout);
}
Poco::Timespan POP3ClientSession::getTimeout() const
{
return _socket.getReceiveTimeout();
}
void POP3ClientSession::login(const std::string& username, const std::string& password)
{
std::string response;
_socket.receiveMessage(response);
if (!isPositive(response)) throw POP3Exception("The POP3 service is unavailable", response);
sendCommand("USER", username, response);
if (!isPositive(response)) throw POP3Exception("Login rejected for user", response);
sendCommand("PASS", password, response);
if (!isPositive(response)) throw POP3Exception("Password rejected for user", response);
}
void POP3ClientSession::close()
{
if (_isOpen)
{
std::string response;
sendCommand("QUIT", response);
_socket.close();
_isOpen = false;
}
}
int POP3ClientSession::messageCount()
{
std::string response;
sendCommand("STAT", response);
if (!isPositive(response)) throw POP3Exception("Cannot determine message count", response);
std::string::const_iterator it = response.begin();
std::string::const_iterator end = response.end();
int count = 0;
while (it != end && !Poco::Ascii::isSpace(*it)) ++it;
while (it != end && Poco::Ascii::isSpace(*it)) ++it;
while (it != end && Poco::Ascii::isDigit(*it)) count = count*10 + *it++ - '0';
return count;
}
void POP3ClientSession::listMessages(MessageInfoVec& messages)
{
messages.clear();
std::string response;
sendCommand("LIST", response);
if (!isPositive(response)) throw POP3Exception("Cannot get message list", response);
_socket.receiveMessage(response);
while (response != ".")
{
MessageInfo info = {0, 0};
std::string::const_iterator it = response.begin();
std::string::const_iterator end = response.end();
while (it != end && Poco::Ascii::isDigit(*it)) info.id = info.id*10 + *it++ - '0';
while (it != end && Poco::Ascii::isSpace(*it)) ++it;
while (it != end && Poco::Ascii::isDigit(*it)) info.size = info.size*10 + *it++ - '0';
messages.push_back(info);
_socket.receiveMessage(response);
}
}
void POP3ClientSession::retrieveMessage(int id, MailMessage& message)
{
std::string response;
sendCommand("RETR", NumberFormatter::format(id), response);
if (!isPositive(response)) throw POP3Exception("Cannot retrieve message", response);
DialogInputStream sis(_socket);
MailInputStream mis(sis);
message.read(mis);
while (mis.good()) mis.get(); // read any remaining junk
}
void POP3ClientSession::retrieveMessage(int id, MailMessage& message, PartHandler& handler)
{
std::string response;
sendCommand("RETR", NumberFormatter::format(id), response);
if (!isPositive(response)) throw POP3Exception("Cannot retrieve message", response);
DialogInputStream sis(_socket);
MailInputStream mis(sis);
message.read(mis, handler);
while (mis.good()) mis.get(); // read any remaining junk
}
void POP3ClientSession::retrieveMessage(int id, std::ostream& ostr)
{
std::string response;
sendCommand("RETR", NumberFormatter::format(id), response);
if (!isPositive(response)) throw POP3Exception("Cannot retrieve message", response);
DialogInputStream sis(_socket);
MailInputStream mis(sis);
StreamCopier::copyStream(mis, ostr);
}
void POP3ClientSession::retrieveHeader(int id, MessageHeader& header)
{
std::string response;
sendCommand("TOP", NumberFormatter::format(id), "0", response);
if (!isPositive(response)) throw POP3Exception("Cannot retrieve header", response);
DialogInputStream sis(_socket);
MailInputStream mis(sis);
header.read(mis);
// skip stuff following header
mis.get(); // \r
mis.get(); // \n
}
void POP3ClientSession::deleteMessage(int id)
{
std::string response;
sendCommand("DELE", NumberFormatter::format(id), response);
if (!isPositive(response)) throw POP3Exception("Cannot mark message for deletion", response);
}
bool POP3ClientSession::sendCommand(const std::string& command, std::string& response)
{
_socket.sendMessage(command);
_socket.receiveMessage(response);
return isPositive(response);
}
bool POP3ClientSession::sendCommand(const std::string& command, const std::string& arg, std::string& response)
{
_socket.sendMessage(command, arg);
_socket.receiveMessage(response);
return isPositive(response);
}
bool POP3ClientSession::sendCommand(const std::string& command, const std::string& arg1, const std::string& arg2, std::string& response)
{
_socket.sendMessage(command, arg1, arg2);
_socket.receiveMessage(response);
return isPositive(response);
}
bool POP3ClientSession::isPositive(const std::string& response)
{
return response.length() > 0 && response[0] == '+';
}
} } // namespace Poco::Net
+32
View File
@@ -0,0 +1,32 @@
//
// PartHandler.cpp
//
// Library: Net
// Package: Messages
// Module: PartHandler
//
// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/PartHandler.h"
namespace Poco {
namespace Net {
PartHandler::PartHandler()
{
}
PartHandler::~PartHandler()
{
}
} } // namespace Poco::Net
+58
View File
@@ -0,0 +1,58 @@
//
// PartSource.cpp
//
// Library: Net
// Package: Messages
// Module: PartSource
//
// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/PartSource.h"
namespace Poco {
namespace Net {
const int PartSource::UNKNOWN_CONTENT_LENGTH = -1;
PartSource::PartSource():
_mediaType("application/octet-stream")
{
}
PartSource::PartSource(const std::string& mediaType):
_mediaType(mediaType)
{
}
PartSource::~PartSource()
{
}
namespace
{
static const std::string EMPTY;
}
const std::string& PartSource::filename() const
{
return EMPTY;
}
std::streamsize PartSource::getContentLength() const
{
return UNKNOWN_CONTENT_LENGTH;
}
} } // namespace Poco::Net
+87
View File
@@ -0,0 +1,87 @@
//
// PartStore.cpp
//
// Library: Net
// Package: Messages
// Module: PartStore
//
// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/PartStore.h"
#include "Poco/TemporaryFile.h"
#include "Poco/File.h"
#include "Poco/Exception.h"
namespace Poco {
namespace Net {
//
// PartStore
//
PartStore::PartStore(const std::string& mediaType): PartSource(mediaType)
{
}
PartStore::~PartStore()
{
}
//
// FilePartStore
//
FilePartStore::FilePartStore(const std::string& content, const std::string& mediaType, const std::string& filename):
PartStore(mediaType),
_filename(filename),
_path(TemporaryFile::tempName()),
_fstr(_path)
{
_fstr << content << std::flush;
_fstr.seekg(0, std::ios::beg);
}
FilePartStore::~FilePartStore()
{
try
{
_fstr.close();
File(_path).remove();
}
catch (...)
{
}
}
std::istream& FilePartStore::stream()
{
return _fstr;
}
const std::string& FilePartStore::filename() const
{
return _filename;
}
const std::string& FilePartStore::path() const
{
return _path;
}
} } // namespace Poco::Net
+580
View File
@@ -0,0 +1,580 @@
//
// PollSet.cpp
//
// Library: Net
// Package: Sockets
// Module: PollSet
//
// Copyright (c) 2016, Applied Informatics Software Engineering GmbH.
// All rights reserved.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/PollSet.h"
#include "Poco/Net/SocketImpl.h"
#include "Poco/Mutex.h"
#include <set>
#if defined(_WIN32) && _WIN32_WINNT >= 0x0600
#ifndef POCO_HAVE_FD_POLL
#define POCO_HAVE_FD_POLL 1
#endif
#elif defined(POCO_OS_FAMILY_BSD)
#ifndef POCO_HAVE_FD_POLL
#define POCO_HAVE_FD_POLL 1
#endif
#endif
#if defined(POCO_HAVE_FD_EPOLL)
#include <sys/epoll.h>
#elif defined(POCO_HAVE_FD_POLL)
#ifndef _WIN32
#include <poll.h>
#endif
#endif
namespace Poco {
namespace Net {
#if defined(POCO_HAVE_FD_EPOLL)
//
// Linux implementation using epoll
//
class PollSetImpl
{
public:
PollSetImpl():
_epollfd(-1),
_events(1024)
{
_epollfd = epoll_create(1);
if (_epollfd < 0)
{
SocketImpl::error();
}
}
~PollSetImpl()
{
if (_epollfd >= 0)
::close(_epollfd);
}
void add(const Socket& socket, int mode)
{
Poco::FastMutex::ScopedLock lock(_mutex);
SocketImpl* sockImpl = socket.impl();
poco_socket_t fd = sockImpl->sockfd();
struct epoll_event ev;
ev.events = 0;
if (mode & PollSet::POLL_READ)
ev.events |= EPOLLIN;
if (mode & PollSet::POLL_WRITE)
ev.events |= EPOLLOUT;
if (mode & PollSet::POLL_ERROR)
ev.events |= EPOLLERR;
ev.data.ptr = socket.impl();
int err = epoll_ctl(_epollfd, EPOLL_CTL_ADD, fd, &ev);
if (err)
{
if (errno == EEXIST) update(socket, mode);
else SocketImpl::error();
}
if (_socketMap.find(sockImpl) == _socketMap.end())
_socketMap[sockImpl] = socket;
}
void remove(const Socket& socket)
{
Poco::FastMutex::ScopedLock lock(_mutex);
poco_socket_t fd = socket.impl()->sockfd();
struct epoll_event ev;
ev.events = 0;
ev.data.ptr = 0;
int err = epoll_ctl(_epollfd, EPOLL_CTL_DEL, fd, &ev);
if (err) SocketImpl::error();
_socketMap.erase(socket.impl());
}
bool has(const Socket& socket) const
{
Poco::FastMutex::ScopedLock lock(_mutex);
SocketImpl* sockImpl = socket.impl();
return sockImpl &&
(_socketMap.find(sockImpl) != _socketMap.end());
}
bool empty() const
{
Poco::FastMutex::ScopedLock lock(_mutex);
return _socketMap.empty();
}
void update(const Socket& socket, int mode)
{
poco_socket_t fd = socket.impl()->sockfd();
struct epoll_event ev;
ev.events = 0;
if (mode & PollSet::POLL_READ)
ev.events |= EPOLLIN;
if (mode & PollSet::POLL_WRITE)
ev.events |= EPOLLOUT;
if (mode & PollSet::POLL_ERROR)
ev.events |= EPOLLERR;
ev.data.ptr = socket.impl();
int err = epoll_ctl(_epollfd, EPOLL_CTL_MOD, fd, &ev);
if (err)
{
SocketImpl::error();
}
}
void clear()
{
Poco::FastMutex::ScopedLock lock(_mutex);
::close(_epollfd);
_socketMap.clear();
_epollfd = epoll_create(1);
if (_epollfd < 0)
{
SocketImpl::error();
}
}
PollSet::SocketModeMap poll(const Poco::Timespan& timeout)
{
PollSet::SocketModeMap result;
{
Poco::FastMutex::ScopedLock lock(_mutex);
if(_socketMap.empty()) return result;
}
Poco::Timespan remainingTime(timeout);
int rc;
do
{
Poco::Timestamp start;
rc = epoll_wait(_epollfd, &_events[0], _events.size(), remainingTime.totalMilliseconds());
if (rc < 0 && SocketImpl::lastError() == POCO_EINTR)
{
Poco::Timestamp end;
Poco::Timespan waited = end - start;
if (waited < remainingTime)
remainingTime -= waited;
else
remainingTime = 0;
}
}
while (rc < 0 && SocketImpl::lastError() == POCO_EINTR);
if (rc < 0) SocketImpl::error();
Poco::FastMutex::ScopedLock lock(_mutex);
for (int i = 0; i < rc; i++)
{
std::map<void*, Socket>::iterator it = _socketMap.find(_events[i].data.ptr);
if (it != _socketMap.end())
{
if (_events[i].events & EPOLLIN)
result[it->second] |= PollSet::POLL_READ;
if (_events[i].events & EPOLLOUT)
result[it->second] |= PollSet::POLL_WRITE;
if (_events[i].events & EPOLLERR)
result[it->second] |= PollSet::POLL_ERROR;
}
}
return result;
}
private:
mutable Poco::FastMutex _mutex;
int _epollfd;
std::map<void*, Socket> _socketMap;
std::vector<struct epoll_event> _events;
};
#elif defined(POCO_HAVE_FD_POLL)
//
// BSD/Windows implementation using poll/WSAPoll
//
class PollSetImpl
{
public:
void add(const Socket& socket, int mode)
{
Poco::FastMutex::ScopedLock lock(_mutex);
poco_socket_t fd = socket.impl()->sockfd();
_addMap[fd] = mode;
_removeSet.erase(fd);
_socketMap[fd] = socket;
}
void remove(const Socket& socket)
{
Poco::FastMutex::ScopedLock lock(_mutex);
poco_socket_t fd = socket.impl()->sockfd();
_removeSet.insert(fd);
_addMap.erase(fd);
_socketMap.erase(fd);
}
bool has(const Socket& socket) const
{
Poco::FastMutex::ScopedLock lock(_mutex);
SocketImpl* sockImpl = socket.impl();
return sockImpl &&
(_socketMap.find(sockImpl->sockfd()) != _socketMap.end());
}
bool empty() const
{
Poco::FastMutex::ScopedLock lock(_mutex);
return _socketMap.empty();
}
void update(const Socket& socket, int mode)
{
Poco::FastMutex::ScopedLock lock(_mutex);
poco_socket_t fd = socket.impl()->sockfd();
for (auto it = _pollfds.begin(); it != _pollfds.end(); ++it)
{
if (it->fd == fd)
{
it->events = 0;
if (mode & PollSet::POLL_READ)
it->events |= POLLIN;
if (mode & PollSet::POLL_WRITE)
it->events |= POLLOUT;
}
}
}
void clear()
{
Poco::FastMutex::ScopedLock lock(_mutex);
_socketMap.clear();
_addMap.clear();
_removeSet.clear();
_pollfds.clear();
}
PollSet::SocketModeMap poll(const Poco::Timespan& timeout)
{
PollSet::SocketModeMap result;
{
Poco::FastMutex::ScopedLock lock(_mutex);
if (!_removeSet.empty())
{
for (auto it = _pollfds.begin(); it != _pollfds.end();)
{
if (_removeSet.find(it->fd) != _removeSet.end())
{
it = _pollfds.erase(it);
}
else ++it;
}
_removeSet.clear();
}
_pollfds.reserve(_pollfds.size() + _addMap.size());
for (auto it = _addMap.begin(); it != _addMap.end(); ++it)
{
pollfd pfd;
pfd.fd = it->first;
pfd.events = 0;
pfd.revents = 0;
if (it->second & PollSet::POLL_READ)
pfd.events |= POLLIN;
if (it->second & PollSet::POLL_WRITE)
pfd.events |= POLLOUT;
_pollfds.push_back(pfd);
}
_addMap.clear();
}
if (_pollfds.empty()) return result;
Poco::Timespan remainingTime(timeout);
int rc;
do
{
Poco::Timestamp start;
#ifdef _WIN32
rc = WSAPoll(&_pollfds[0], static_cast<ULONG>(_pollfds.size()), static_cast<INT>(timeout.totalMilliseconds()));
#else
rc = ::poll(&_pollfds[0], _pollfds.size(), timeout.totalMilliseconds());
#endif
if (rc < 0 && SocketImpl::lastError() == POCO_EINTR)
{
Poco::Timestamp end;
Poco::Timespan waited = end - start;
if (waited < remainingTime)
remainingTime -= waited;
else
remainingTime = 0;
}
}
while (rc < 0 && SocketImpl::lastError() == POCO_EINTR);
if (rc < 0) SocketImpl::error();
{
Poco::FastMutex::ScopedLock lock(_mutex);
if (!_socketMap.empty())
{
for (auto it = _pollfds.begin(); it != _pollfds.end(); ++it)
{
std::map<poco_socket_t, Socket>::const_iterator its = _socketMap.find(it->fd);
if (its != _socketMap.end())
{
if (it->revents & POLLIN)
result[its->second] |= PollSet::POLL_READ;
if (it->revents & POLLOUT)
result[its->second] |= PollSet::POLL_WRITE;
if (it->revents & POLLERR)
result[its->second] |= PollSet::POLL_ERROR;
#ifdef _WIN32
if (it->revents & POLLHUP)
result[its->second] |= PollSet::POLL_READ;
#endif
}
it->revents = 0;
}
}
}
return result;
}
private:
mutable Poco::FastMutex _mutex;
std::map<poco_socket_t, Socket> _socketMap;
std::map<poco_socket_t, int> _addMap;
std::set<poco_socket_t> _removeSet;
std::vector<pollfd> _pollfds;
};
#else
//
// Fallback implementation using select()
//
class PollSetImpl
{
public:
void add(const Socket& socket, int mode)
{
Poco::FastMutex::ScopedLock lock(_mutex);
_map[socket] = mode;
}
void remove(const Socket& socket)
{
Poco::FastMutex::ScopedLock lock(_mutex);
_map.erase(socket);
}
bool has(const Socket& socket) const
{
Poco::FastMutex::ScopedLock lock(_mutex);
return _map.find(socket) != _map.end();
}
bool empty() const
{
Poco::FastMutex::ScopedLock lock(_mutex);
return _map.empty();
}
void update(const Socket& socket, int mode)
{
Poco::FastMutex::ScopedLock lock(_mutex);
_map[socket] = mode;
}
void clear()
{
Poco::FastMutex::ScopedLock lock(_mutex);
_map.clear();
}
PollSet::SocketModeMap poll(const Poco::Timespan& timeout)
{
fd_set fdRead;
fd_set fdWrite;
fd_set fdExcept;
int nfd = 0;
FD_ZERO(&fdRead);
FD_ZERO(&fdWrite);
FD_ZERO(&fdExcept);
{
Poco::FastMutex::ScopedLock lock(_mutex);
for (auto it = _map.begin(); it != _map.end(); ++it)
{
poco_socket_t fd = it->first.impl()->sockfd();
if (fd != POCO_INVALID_SOCKET && it->second)
{
if (int(fd) > nfd) nfd = int(fd);
if (it->second & PollSet::POLL_READ)
{
FD_SET(fd, &fdRead);
}
if (it->second & PollSet::POLL_WRITE)
{
FD_SET(fd, &fdWrite);
}
if (it->second & PollSet::POLL_ERROR)
{
FD_SET(fd, &fdExcept);
}
}
}
}
PollSet::SocketModeMap result;
if (nfd == 0) return result;
Poco::Timespan remainingTime(timeout);
int rc;
do
{
struct timeval tv;
tv.tv_sec = (long) remainingTime.totalSeconds();
tv.tv_usec = (long) remainingTime.useconds();
Poco::Timestamp start;
rc = ::select(nfd + 1, &fdRead, &fdWrite, &fdExcept, &tv);
if (rc < 0 && SocketImpl::lastError() == POCO_EINTR)
{
Poco::Timestamp end;
Poco::Timespan waited = end - start;
if (waited < remainingTime)
remainingTime -= waited;
else
remainingTime = 0;
}
}
while (rc < 0 && SocketImpl::lastError() == POCO_EINTR);
if (rc < 0) SocketImpl::error();
{
Poco::FastMutex::ScopedLock lock(_mutex);
for (auto it = _map.begin(); it != _map.end(); ++it)
{
poco_socket_t fd = it->first.impl()->sockfd();
if (fd != POCO_INVALID_SOCKET)
{
if (FD_ISSET(fd, &fdRead))
{
result[it->first] |= PollSet::POLL_READ;
}
if (FD_ISSET(fd, &fdWrite))
{
result[it->first] |= PollSet::POLL_WRITE;
}
if (FD_ISSET(fd, &fdExcept))
{
result[it->first] |= PollSet::POLL_ERROR;
}
}
}
}
return result;
}
private:
mutable Poco::FastMutex _mutex;
PollSet::SocketModeMap _map;
};
#endif
PollSet::PollSet():
_pImpl(new PollSetImpl)
{
}
PollSet::~PollSet()
{
delete _pImpl;
}
void PollSet::add(const Socket& socket, int mode)
{
_pImpl->add(socket, mode);
}
void PollSet::remove(const Socket& socket)
{
_pImpl->remove(socket);
}
void PollSet::update(const Socket& socket, int mode)
{
_pImpl->update(socket, mode);
}
bool PollSet::has(const Socket& socket) const
{
return _pImpl->has(socket);
}
bool PollSet::empty() const
{
return _pImpl->empty();
}
void PollSet::clear()
{
_pImpl->clear();
}
PollSet::SocketModeMap PollSet::poll(const Poco::Timespan& timeout)
{
return _pImpl->poll(timeout);
}
} } // namespace Poco::Net
+102
View File
@@ -0,0 +1,102 @@
//
// QuotedPrintableDecoder.cpp
//
// Library: Net
// Package: Messages
// Module: QuotedPrintableDecoder
//
// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/QuotedPrintableDecoder.h"
#include "Poco/NumberParser.h"
#include "Poco/Exception.h"
#include "Poco/Ascii.h"
using Poco::UnbufferedStreamBuf;
using Poco::NumberParser;
using Poco::DataFormatException;
namespace Poco {
namespace Net {
QuotedPrintableDecoderBuf::QuotedPrintableDecoderBuf(std::istream& istr):
_buf(*istr.rdbuf())
{
}
QuotedPrintableDecoderBuf::~QuotedPrintableDecoderBuf()
{
}
int QuotedPrintableDecoderBuf::readFromDevice()
{
int ch = _buf.sbumpc();
while (ch == '=')
{
ch = _buf.sbumpc();
if (ch == '\r')
{
_buf.sbumpc(); // read \n
}
else if (Poco::Ascii::isHexDigit(ch))
{
std::string hex = "0x";
hex += (char) ch;
ch = _buf.sbumpc();
if (Poco::Ascii::isHexDigit(ch))
{
hex += (char) ch;
return NumberParser::parseHex(hex);
}
throw DataFormatException("Incomplete hex number in quoted-printable encoded stream");
}
else if (ch != '\n')
{
throw DataFormatException("Invalid occurrence of '=' in quoted-printable encoded stream");
}
ch = _buf.sbumpc();
}
return ch;
}
QuotedPrintableDecoderIOS::QuotedPrintableDecoderIOS(std::istream& istr): _buf(istr)
{
poco_ios_init(&_buf);
}
QuotedPrintableDecoderIOS::~QuotedPrintableDecoderIOS()
{
}
QuotedPrintableDecoderBuf* QuotedPrintableDecoderIOS::rdbuf()
{
return &_buf;
}
QuotedPrintableDecoder::QuotedPrintableDecoder(std::istream& istr):
QuotedPrintableDecoderIOS(istr),
std::istream(&_buf)
{
}
QuotedPrintableDecoder::~QuotedPrintableDecoder()
{
}
} } // namespace Poco::Net
+150
View File
@@ -0,0 +1,150 @@
//
// QuotedPrintableEncoder.cpp
//
// Library: Net
// Package: Messages
// Module: QuotedPrintableEncoder
//
// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/QuotedPrintableEncoder.h"
#include "Poco/NumberFormatter.h"
using Poco::UnbufferedStreamBuf;
using Poco::NumberFormatter;
namespace Poco {
namespace Net {
QuotedPrintableEncoderBuf::QuotedPrintableEncoderBuf(std::ostream& ostr):
_pending(-1),
_lineLength(0),
_ostr(ostr)
{
}
QuotedPrintableEncoderBuf::~QuotedPrintableEncoderBuf()
{
try
{
close();
}
catch (...)
{
}
}
int QuotedPrintableEncoderBuf::writeToDevice(char c)
{
if (_pending != -1)
{
if (_pending == '\r' && c == '\n')
writeRaw((char) _pending);
else if (c == '\r' || c == '\n')
writeEncoded((char) _pending);
else
writeRaw((char) _pending);
_pending = -1;
}
if (c == '\t' || c == ' ')
{
_pending = charToInt(c);
return _pending;
}
else if (c == '\r' || c == '\n' || (c > 32 && c < 127 && c != '='))
{
writeRaw(c);
}
else
{
writeEncoded(c);
}
return charToInt(c);
}
void QuotedPrintableEncoderBuf::writeEncoded(char c)
{
if (_lineLength >= 73)
{
_ostr << "=\r\n";
_lineLength = 3;
}
else _lineLength += 3;
_ostr << '=' << NumberFormatter::formatHex((unsigned) charToInt(c), 2);
}
void QuotedPrintableEncoderBuf::writeRaw(char c)
{
if (c == '\r' || c == '\n')
{
_ostr.put(c);
_lineLength = 0;
}
else if (_lineLength < 75)
{
_ostr.put(c);
++_lineLength;
}
else
{
_ostr << "=\r\n" << c;
_lineLength = 1;
}
}
int QuotedPrintableEncoderBuf::close()
{
sync();
return _ostr ? 0 : -1;
}
QuotedPrintableEncoderIOS::QuotedPrintableEncoderIOS(std::ostream& ostr): _buf(ostr)
{
poco_ios_init(&_buf);
}
QuotedPrintableEncoderIOS::~QuotedPrintableEncoderIOS()
{
}
int QuotedPrintableEncoderIOS::close()
{
return _buf.close();
}
QuotedPrintableEncoderBuf* QuotedPrintableEncoderIOS::rdbuf()
{
return &_buf;
}
QuotedPrintableEncoder::QuotedPrintableEncoder(std::ostream& ostr):
QuotedPrintableEncoderIOS(ostr),
std::ostream(&_buf)
{
}
QuotedPrintableEncoder::~QuotedPrintableEncoder()
{
}
} } // namespace Poco::Net
+117
View File
@@ -0,0 +1,117 @@
//
// RawSocket.cpp
//
// Library: Net
// Package: Sockets
// Module: RawSocket
//
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/RawSocket.h"
#include "Poco/Net/RawSocketImpl.h"
#include "Poco/Exception.h"
using Poco::InvalidArgumentException;
namespace Poco {
namespace Net {
RawSocket::RawSocket():
Socket(new RawSocketImpl)
{
}
RawSocket::RawSocket(SocketAddress::Family family, int proto):
Socket(new RawSocketImpl(family, proto))
{
}
RawSocket::RawSocket(const SocketAddress& address, bool reuseAddress):
Socket(new RawSocketImpl(address.family()))
{
bind(address, reuseAddress);
}
RawSocket::RawSocket(const Socket& socket): Socket(socket)
{
if (!dynamic_cast<RawSocketImpl*>(impl()))
throw InvalidArgumentException("Cannot assign incompatible socket");
}
RawSocket::RawSocket(SocketImpl* pImpl): Socket(pImpl)
{
if (!dynamic_cast<RawSocketImpl*>(impl()))
throw InvalidArgumentException("Cannot assign incompatible socket");
}
RawSocket::~RawSocket()
{
}
RawSocket& RawSocket::operator = (const Socket& socket)
{
if (dynamic_cast<RawSocketImpl*>(socket.impl()))
Socket::operator = (socket);
else
throw InvalidArgumentException("Cannot assign incompatible socket");
return *this;
}
void RawSocket::connect(const SocketAddress& address)
{
impl()->connect(address);
}
void RawSocket::bind(const SocketAddress& address, bool reuseAddress)
{
impl()->bind(address, reuseAddress);
}
void RawSocket::bind(const SocketAddress& address, bool reuseAddress, bool reusePort)
{
impl()->bind(address, reuseAddress, reusePort);
}
int RawSocket::sendBytes(const void* buffer, int length, int flags)
{
return impl()->sendBytes(buffer, length, flags);
}
int RawSocket::receiveBytes(void* buffer, int length, int flags)
{
return impl()->receiveBytes(buffer, length, flags);
}
int RawSocket::sendTo(const void* buffer, int length, const SocketAddress& address, int flags)
{
return impl()->sendTo(buffer, length, address, flags);
}
int RawSocket::receiveFrom(void* buffer, int length, SocketAddress& address, int flags)
{
return impl()->receiveFrom(buffer, length, address, flags);
}
} } // namespace Poco::Net
+69
View File
@@ -0,0 +1,69 @@
//
// RawSocketImpl.cpp
//
// Library: Net
// Package: Sockets
// Module: RawSocketImpl
//
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/RawSocketImpl.h"
#include "Poco/Net/NetException.h"
using Poco::InvalidArgumentException;
namespace Poco {
namespace Net {
RawSocketImpl::RawSocketImpl()
{
init(AF_INET);
}
RawSocketImpl::RawSocketImpl(SocketAddress::Family family, int proto)
{
if (family == SocketAddress::IPv4)
init2(AF_INET, proto);
#if defined(POCO_HAVE_IPv6)
else if (family == SocketAddress::IPv6)
init2(AF_INET6, proto);
#endif
else throw InvalidArgumentException("Invalid or unsupported address family passed to RawSocketImpl");
}
RawSocketImpl::RawSocketImpl(poco_socket_t sockfd):
SocketImpl(sockfd)
{
}
RawSocketImpl::~RawSocketImpl()
{
}
void RawSocketImpl::init(int af)
{
init2(af, IPPROTO_RAW);
}
void RawSocketImpl::init2(int af, int proto)
{
initSocket(af, SOCK_RAW, proto);
setOption(IPPROTO_IP, IP_HDRINCL, 0);
}
} } // namespace Poco::Net
+355
View File
@@ -0,0 +1,355 @@
//
// RemoteSyslogChannel.cpp
//
// Library: Net
// Package: Logging
// Module: RemoteSyslogChannel
//
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/RemoteSyslogChannel.h"
#include "Poco/Message.h"
#include "Poco/DateTimeFormatter.h"
#include "Poco/NumberFormatter.h"
#include "Poco/Net/SocketAddress.h"
#include "Poco/Net/DNS.h"
#include "Poco/LoggingFactory.h"
#include "Poco/Instantiator.h"
#include "Poco/String.h"
namespace Poco {
namespace Net {
const std::string RemoteSyslogChannel::BSD_TIMEFORMAT("%b %f %H:%M:%S");
const std::string RemoteSyslogChannel::SYSLOG_TIMEFORMAT("%Y-%m-%dT%H:%M:%S.%i%z");
const std::string RemoteSyslogChannel::PROP_NAME("name");
const std::string RemoteSyslogChannel::PROP_FACILITY("facility");
const std::string RemoteSyslogChannel::PROP_FORMAT("format");
const std::string RemoteSyslogChannel::PROP_LOGHOST("loghost");
const std::string RemoteSyslogChannel::PROP_HOST("host");
const std::string RemoteSyslogChannel::STRUCTURED_DATA("structured-data");
RemoteSyslogChannel::RemoteSyslogChannel():
_logHost("localhost"),
_name("-"),
_facility(SYSLOG_USER),
_bsdFormat(false),
_open(false)
{
}
RemoteSyslogChannel::RemoteSyslogChannel(const std::string& address, const std::string& name, int facility, bool bsdFormat):
_logHost(address),
_name(name),
_facility(facility),
_bsdFormat(bsdFormat),
_open(false)
{
if (_name.empty()) _name = "-";
}
RemoteSyslogChannel::~RemoteSyslogChannel()
{
try
{
close();
}
catch (...)
{
poco_unexpected();
}
}
void RemoteSyslogChannel::open()
{
if (_open) return;
if (_logHost.find(':') != std::string::npos)
_socketAddress = SocketAddress(_logHost);
else
_socketAddress = SocketAddress(_logHost, SYSLOG_PORT);
// reset socket for the case that it has been previously closed
_socket = DatagramSocket(_socketAddress.family());
if (_host.empty())
{
try
{
_host = DNS::thisHost().name();
}
catch (Poco::Exception&)
{
_host = _socket.address().host().toString();
}
}
_open = true;
}
void RemoteSyslogChannel::close()
{
if (_open)
{
_socket.close();
_open = false;
}
}
void RemoteSyslogChannel::log(const Message& msg)
{
Poco::FastMutex::ScopedLock lock(_mutex);
if (!_open) open();
std::string m;
m.reserve(1024);
m += '<';
Poco::NumberFormatter::append(m, getPrio(msg) + _facility);
m += '>';
if (_bsdFormat)
{
Poco::DateTimeFormatter::append(m, msg.getTime(), BSD_TIMEFORMAT);
m += ' ';
m += _host;
}
else
{
m += "1 "; // version
Poco::DateTimeFormatter::append(m, msg.getTime(), SYSLOG_TIMEFORMAT);
m += ' ';
m += _host;
m += ' ';
m += _name;
m += ' ';
Poco::NumberFormatter::append(m, msg.getPid());
m += ' ';
m += msg.getSource();
m += ' ';
if (msg.has(STRUCTURED_DATA))
{
m += msg.get(STRUCTURED_DATA);
}
else
{
m += "-";
}
}
m += ' ';
m += msg.getText();
_socket.sendTo(m.data(), static_cast<int>(m.size()), _socketAddress);
}
void RemoteSyslogChannel::setProperty(const std::string& name, const std::string& value)
{
if (name == PROP_NAME)
{
_name = value;
if (_name.empty()) _name = "-";
}
else if (name == PROP_FACILITY)
{
std::string facility;
if (Poco::icompare(value, 4, "LOG_") == 0)
facility = Poco::toUpper(value.substr(4));
else if (Poco::icompare(value, 4, "SYSLOG_") == 0)
facility = Poco::toUpper(value.substr(7));
else
facility = Poco::toUpper(value);
if (facility == "KERN")
_facility = SYSLOG_KERN;
else if (facility == "USER")
_facility = SYSLOG_USER;
else if (facility == "MAIL")
_facility = SYSLOG_MAIL;
else if (facility == "DAEMON")
_facility = SYSLOG_DAEMON;
else if (facility == "AUTH")
_facility = SYSLOG_AUTH;
else if (facility == "AUTHPRIV")
_facility = SYSLOG_AUTHPRIV;
else if (facility == "SYSLOG")
_facility = SYSLOG_SYSLOG;
else if (facility == "LPR")
_facility = SYSLOG_LPR;
else if (facility == "NEWS")
_facility = SYSLOG_NEWS;
else if (facility == "UUCP")
_facility = SYSLOG_UUCP;
else if (facility == "CRON")
_facility = SYSLOG_CRON;
else if (facility == "FTP")
_facility = SYSLOG_FTP;
else if (facility == "NTP")
_facility = SYSLOG_NTP;
else if (facility == "LOGAUDIT")
_facility = SYSLOG_LOGAUDIT;
else if (facility == "LOGALERT")
_facility = SYSLOG_LOGALERT;
else if (facility == "CLOCK")
_facility = SYSLOG_CLOCK;
else if (facility == "LOCAL0")
_facility = SYSLOG_LOCAL0;
else if (facility == "LOCAL1")
_facility = SYSLOG_LOCAL1;
else if (facility == "LOCAL2")
_facility = SYSLOG_LOCAL2;
else if (facility == "LOCAL3")
_facility = SYSLOG_LOCAL3;
else if (facility == "LOCAL4")
_facility = SYSLOG_LOCAL4;
else if (facility == "LOCAL5")
_facility = SYSLOG_LOCAL5;
else if (facility == "LOCAL6")
_facility = SYSLOG_LOCAL6;
else if (facility == "LOCAL7")
_facility = SYSLOG_LOCAL7;
}
else if (name == PROP_LOGHOST)
{
_logHost = value;
}
else if (name == PROP_HOST)
{
_host = value;
}
else if (name == PROP_FORMAT)
{
_bsdFormat = (value == "bsd" || value == "rfc3164");
}
else
{
Channel::setProperty(name, value);
}
}
std::string RemoteSyslogChannel::getProperty(const std::string& name) const
{
if (name == PROP_NAME)
{
if (_name != "-")
return _name;
else
return "";
}
else if (name == PROP_FACILITY)
{
if (_facility == SYSLOG_KERN)
return "KERN";
else if (_facility == SYSLOG_USER)
return "USER";
else if (_facility == SYSLOG_MAIL)
return "MAIL";
else if (_facility == SYSLOG_DAEMON)
return "DAEMON";
else if (_facility == SYSLOG_AUTH)
return "AUTH";
else if (_facility == SYSLOG_AUTHPRIV)
return "AUTHPRIV";
else if (_facility == SYSLOG_SYSLOG)
return "SYSLOG";
else if (_facility == SYSLOG_LPR)
return "LPR";
else if (_facility == SYSLOG_NEWS)
return "NEWS";
else if (_facility == SYSLOG_UUCP)
return "UUCP";
else if (_facility == SYSLOG_CRON)
return "CRON";
else if (_facility == SYSLOG_FTP)
return "FTP";
else if (_facility == SYSLOG_NTP)
return "NTP";
else if (_facility == SYSLOG_LOGAUDIT)
return "LOGAUDIT";
else if (_facility == SYSLOG_LOGALERT)
return "LOGALERT";
else if (_facility == SYSLOG_CLOCK)
return "CLOCK";
else if (_facility == SYSLOG_LOCAL0)
return "LOCAL0";
else if (_facility == SYSLOG_LOCAL1)
return "LOCAL1";
else if (_facility == SYSLOG_LOCAL2)
return "LOCAL2";
else if (_facility == SYSLOG_LOCAL3)
return "LOCAL3";
else if (_facility == SYSLOG_LOCAL4)
return "LOCAL4";
else if (_facility == SYSLOG_LOCAL5)
return "LOCAL5";
else if (_facility == SYSLOG_LOCAL6)
return "LOCAL6";
else if (_facility == SYSLOG_LOCAL7)
return "LOCAL7";
else
return "";
}
else if (name == PROP_LOGHOST)
{
return _logHost;
}
else if (name == PROP_HOST)
{
return _host;
}
else if (name == PROP_FORMAT)
{
return _bsdFormat ? "rfc3164" : "rfc5424";
}
else
{
return Channel::getProperty(name);
}
}
int RemoteSyslogChannel::getPrio(const Message& msg)
{
switch (msg.getPriority())
{
case Message::PRIO_TRACE:
case Message::PRIO_DEBUG:
return SYSLOG_DEBUG;
case Message::PRIO_INFORMATION:
return SYSLOG_INFORMATIONAL;
case Message::PRIO_NOTICE:
return SYSLOG_NOTICE;
case Message::PRIO_WARNING:
return SYSLOG_WARNING;
case Message::PRIO_ERROR:
return SYSLOG_ERROR;
case Message::PRIO_CRITICAL:
return SYSLOG_CRITICAL;
case Message::PRIO_FATAL:
return SYSLOG_ALERT;
default:
return 0;
}
}
void RemoteSyslogChannel::registerChannel()
{
Poco::LoggingFactory::defaultFactory().registerChannelClass("RemoteSyslogChannel", new Poco::Instantiator<RemoteSyslogChannel, Poco::Channel>);
}
} } // namespace Poco::Net
+630
View File
@@ -0,0 +1,630 @@
//
// RemoteSyslogListener.cpp
//
// Library: Net
// Package: Logging
// Module: RemoteSyslogListener
//
// Copyright (c) 2007, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/RemoteSyslogListener.h"
#include "Poco/Net/RemoteSyslogChannel.h"
#include "Poco/Net/DatagramSocket.h"
#include "Poco/Net/SocketAddress.h"
#include "Poco/Runnable.h"
#include "Poco/Notification.h"
#include "Poco/AutoPtr.h"
#include "Poco/NumberParser.h"
#include "Poco/NumberFormatter.h"
#include "Poco/DateTimeParser.h"
#include "Poco/Message.h"
#include "Poco/LoggingFactory.h"
#include "Poco/Buffer.h"
#include "Poco/Ascii.h"
#include <cstddef>
namespace Poco {
namespace Net {
//
// MessageNotification
//
class MessageNotification: public Poco::Notification
{
public:
MessageNotification(const char* buffer, std::size_t length, const Poco::Net::SocketAddress& sourceAddress):
_message(buffer, length),
_sourceAddress(sourceAddress)
{
}
MessageNotification(const std::string& message, const Poco::Net::SocketAddress& sourceAddress):
_message(message),
_sourceAddress(sourceAddress)
{
}
~MessageNotification()
{
}
const std::string& message() const
{
return _message;
}
const Poco::Net::SocketAddress& sourceAddress() const
{
return _sourceAddress;
}
private:
std::string _message;
Poco::Net::SocketAddress _sourceAddress;
};
//
// RemoteUDPListener
//
class RemoteUDPListener: public Poco::Runnable
{
public:
enum
{
WAITTIME_MILLISEC = 1000,
BUFFER_SIZE = 65536
};
RemoteUDPListener(Poco::NotificationQueue& queue, Poco::UInt16 port);
~RemoteUDPListener();
void run();
void safeStop();
private:
Poco::NotificationQueue& _queue;
DatagramSocket _socket;
bool _stopped;
};
RemoteUDPListener::RemoteUDPListener(Poco::NotificationQueue& queue, Poco::UInt16 port):
_queue(queue),
_socket(Poco::Net::SocketAddress(Poco::Net::IPAddress(), port)),
_stopped(false)
{
}
RemoteUDPListener::~RemoteUDPListener()
{
}
void RemoteUDPListener::run()
{
Poco::Buffer<char> buffer(BUFFER_SIZE);
Poco::Timespan waitTime(WAITTIME_MILLISEC* 1000);
while (!_stopped)
{
try
{
if (_socket.poll(waitTime, Socket::SELECT_READ))
{
Poco::Net::SocketAddress sourceAddress;
int n = _socket.receiveFrom(buffer.begin(), BUFFER_SIZE, sourceAddress);
if (n > 0)
{
_queue.enqueueNotification(new MessageNotification(buffer.begin(), n, sourceAddress));
}
}
}
catch (...)
{
// lazy exception catching
}
}
}
void RemoteUDPListener::safeStop()
{
_stopped = true;
}
//
// SyslogParser
//
class SyslogParser: public Poco::Runnable
{
public:
static const std::string NILVALUE;
enum
{
WAITTIME_MILLISEC = 1000
};
SyslogParser(Poco::NotificationQueue& queue, RemoteSyslogListener* pListener);
~SyslogParser();
void parse(const std::string& line, Poco::Message& message);
void run();
void safeStop();
static Poco::Message::Priority convert(RemoteSyslogChannel::Severity severity);
private:
void parsePrio(const std::string& line, std::size_t& pos, RemoteSyslogChannel::Severity& severity, RemoteSyslogChannel::Facility& fac);
void parseNew(const std::string& line, RemoteSyslogChannel::Severity severity, RemoteSyslogChannel::Facility fac, std::size_t& pos, Poco::Message& message);
void parseBSD(const std::string& line, RemoteSyslogChannel::Severity severity, RemoteSyslogChannel::Facility fac, std::size_t& pos, Poco::Message& message);
static std::string parseUntilSpace(const std::string& line, std::size_t& pos);
/// Parses until it encounters the next space char, returns the string from pos, excluding space
/// pos will point past the space char
static std::string parseStructuredData(const std::string& line, std::size_t& pos);
/// Parses the structured data field.
static std::string parseStructuredDataToken(const std::string& line, std::size_t& pos);
/// Parses a token from the structured data field.
private:
Poco::NotificationQueue& _queue;
bool _stopped;
RemoteSyslogListener* _pListener;
};
const std::string SyslogParser::NILVALUE("-");
SyslogParser::SyslogParser(Poco::NotificationQueue& queue, RemoteSyslogListener* pListener):
_queue(queue),
_stopped(false),
_pListener(pListener)
{
poco_check_ptr (_pListener);
}
SyslogParser::~SyslogParser()
{
}
void SyslogParser::run()
{
while (!_stopped)
{
try
{
Poco::AutoPtr<Poco::Notification> pNf(_queue.waitDequeueNotification(WAITTIME_MILLISEC));
if (pNf)
{
Poco::AutoPtr<MessageNotification> pMsgNf = pNf.cast<MessageNotification>();
Poco::Message message;
parse(pMsgNf->message(), message);
message["addr"] =pMsgNf->sourceAddress().host().toString();
_pListener->log(message);
}
}
catch (Poco::Exception&)
{
// parsing exception, what should we do?
}
catch (...)
{
}
}
}
void SyslogParser::safeStop()
{
_stopped = true;
}
void SyslogParser::parse(const std::string& line, Poco::Message& message)
{
// <int> -> int: lower 3 bits severity, upper bits: facility
std::size_t pos = 0;
RemoteSyslogChannel::Severity severity;
RemoteSyslogChannel::Facility fac;
parsePrio(line, pos, severity, fac);
// the next field decide if we parse an old BSD message or a new syslog message
// BSD: expects a month value in string form: Jan, Feb...
// SYSLOG expects a version number: 1
if (Poco::Ascii::isDigit(line[pos]))
{
parseNew(line, severity, fac, pos, message);
}
else
{
parseBSD(line, severity, fac, pos, message);
}
poco_assert (pos == line.size());
}
void SyslogParser::parsePrio(const std::string& line, std::size_t& pos, RemoteSyslogChannel::Severity& severity, RemoteSyslogChannel::Facility& fac)
{
poco_assert (pos < line.size());
poco_assert (line[pos] == '<');
++pos;
std::size_t start = pos;
while (pos < line.size() && Poco::Ascii::isDigit(line[pos]))
++pos;
poco_assert (line[pos] == '>');
poco_assert (pos - start > 0);
std::string valStr = line.substr(start, pos - start);
++pos; // skip the >
int val = Poco::NumberParser::parse(valStr);
poco_assert (val >= 0 && val <= (RemoteSyslogChannel::SYSLOG_LOCAL7 + RemoteSyslogChannel::SYSLOG_DEBUG));
Poco::UInt16 pri = static_cast<Poco::UInt16>(val);
// now get the lowest 3 bits
severity = static_cast<RemoteSyslogChannel::Severity>(pri & 0x0007u);
fac = static_cast<RemoteSyslogChannel::Facility>(pri & 0xfff8u);
}
void SyslogParser::parseNew(const std::string& line, RemoteSyslogChannel::Severity severity, RemoteSyslogChannel::Facility fac, std::size_t& pos, Poco::Message& message)
{
Poco::Message::Priority prio = convert(severity);
// rest of the unparsed header is:
// VERSION SP TIMESTAMP SP HOSTNAME SP APP-NAME SP PROCID SP MSGID
std::string versionStr(parseUntilSpace(line, pos));
std::string timeStr(parseUntilSpace(line, pos)); // can be the nilvalue!
std::string hostName(parseUntilSpace(line, pos));
std::string appName(parseUntilSpace(line, pos));
std::string procId(parseUntilSpace(line, pos));
std::string msgId(parseUntilSpace(line, pos));
std::string sd(parseStructuredData(line, pos));
std::string messageText(line.substr(pos));
pos = line.size();
Poco::DateTime date;
int tzd = 0;
bool hasDate = Poco::DateTimeParser::tryParse(RemoteSyslogChannel::SYSLOG_TIMEFORMAT, timeStr, date, tzd);
Poco::Message logEntry(msgId, messageText, prio);
logEntry[RemoteSyslogListener::LOG_PROP_HOST] = hostName;
logEntry[RemoteSyslogListener::LOG_PROP_APP] = appName;
logEntry[RemoteSyslogListener::LOG_PROP_STRUCTURED_DATA] = sd;
if (hasDate)
logEntry.setTime(date.timestamp());
int lval(0);
Poco::NumberParser::tryParse(procId, lval);
logEntry.setPid(lval);
message.swap(logEntry);
}
void SyslogParser::parseBSD(const std::string& line, RemoteSyslogChannel::Severity severity, RemoteSyslogChannel::Facility fac, std::size_t& pos, Poco::Message& message)
{
Poco::Message::Priority prio = convert(severity);
// rest of the unparsed header is:
// "%b %f %H:%M:%S" SP hostname|ipaddress
// detect three spaces
int spaceCnt = 0;
std::size_t start = pos;
while (spaceCnt < 3 && pos < line.size())
{
if (line[pos] == ' ')
{
spaceCnt++;
if (spaceCnt == 1)
{
// size must be 3 chars for month
if (pos - start != 3)
{
// probably a shortened time value, or the hostname
// assume hostName
Poco::Message logEntry(line.substr(start, pos-start), line.substr(pos+1), prio);
message.swap(logEntry);
return;
}
}
else if (spaceCnt == 2)
{
// a day value!
if (!(Poco::Ascii::isDigit(line[pos-1]) && (Poco::Ascii::isDigit(line[pos-2]) || Poco::Ascii::isSpace(line[pos-2]))))
{
// assume the next field is a hostname
spaceCnt = 3;
}
}
if (pos + 1 < line.size() && line[pos+1] == ' ')
{
// we have two spaces when the day value is smaller than 10!
++pos; // skip one
}
}
++pos;
}
std::string timeStr(line.substr(start, pos-start-1));
int tzd(0);
Poco::DateTime date;
int year = date.year(); // year is not included, use the current one
bool hasDate = Poco::DateTimeParser::tryParse(RemoteSyslogChannel::BSD_TIMEFORMAT, timeStr, date, tzd);
if (hasDate)
{
int m = date.month();
int d = date.day();
int h = date.hour();
int min = date.minute();
int sec = date.second();
date = Poco::DateTime(year, m, d, h, min, sec);
}
// next entry is host SP
std::string hostName(parseUntilSpace(line, pos));
// TAG: at most 32 alphanumeric chars, ANY non alphannumeric indicates start of message content
// ignore: treat everything as content
std::string messageText(line.substr(pos));
pos = line.size();
Poco::Message logEntry(hostName, messageText, prio);
logEntry.setTime(date.timestamp());
message.swap(logEntry);
}
std::string SyslogParser::parseUntilSpace(const std::string& line, std::size_t& pos)
{
std::size_t start = pos;
while (pos < line.size() && !Poco::Ascii::isSpace(line[pos]))
++pos;
// skip space
++pos;
return line.substr(start, pos-start-1);
}
std::string SyslogParser::parseStructuredData(const std::string& line, std::size_t& pos)
{
std::string sd;
if (pos < line.size())
{
if (line[pos] == '-')
{
++pos;
}
else if (line[pos] == '[')
{
std::string tok = parseStructuredDataToken(line, pos);
while (tok == "[")
{
sd += tok;
tok = parseStructuredDataToken(line, pos);
while (tok != "]" && !tok.empty())
{
sd += tok;
tok = parseStructuredDataToken(line, pos);
}
sd += tok;
if (pos < line.size() && line[pos] == '[') tok = parseStructuredDataToken(line, pos);
}
}
if (pos < line.size() && Poco::Ascii::isSpace(line[pos])) ++pos;
}
return sd;
}
std::string SyslogParser::parseStructuredDataToken(const std::string& line, std::size_t& pos)
{
std::string tok;
if (pos < line.size())
{
if (Poco::Ascii::isSpace(line[pos]) || line[pos] == '=' || line[pos] == '[' || line[pos] == ']')
{
tok += line[pos++];
}
else if (line[pos] == '"')
{
tok += line[pos++];
while (pos < line.size() && line[pos] != '"')
{
tok += line[pos++];
}
tok += '"';
if (pos < line.size()) pos++;
}
else
{
while (pos < line.size() && !Poco::Ascii::isSpace(line[pos]) && line[pos] != '=')
{
tok += line[pos++];
}
}
}
return tok;
}
Poco::Message::Priority SyslogParser::convert(RemoteSyslogChannel::Severity severity)
{
switch (severity)
{
case RemoteSyslogChannel::SYSLOG_EMERGENCY:
return Poco::Message::PRIO_FATAL;
case RemoteSyslogChannel::SYSLOG_ALERT:
return Poco::Message::PRIO_FATAL;
case RemoteSyslogChannel::SYSLOG_CRITICAL:
return Poco::Message::PRIO_CRITICAL;
case RemoteSyslogChannel::SYSLOG_ERROR:
return Poco::Message::PRIO_ERROR;
case RemoteSyslogChannel::SYSLOG_WARNING:
return Poco::Message::PRIO_WARNING;
case RemoteSyslogChannel::SYSLOG_NOTICE:
return Poco::Message::PRIO_NOTICE;
case RemoteSyslogChannel::SYSLOG_INFORMATIONAL:
return Poco::Message::PRIO_INFORMATION;
case RemoteSyslogChannel::SYSLOG_DEBUG:
return Poco::Message::PRIO_DEBUG;
}
throw Poco::LogicException("Illegal severity value in message");
}
//
// RemoteSyslogListener
//
const std::string RemoteSyslogListener::PROP_PORT("port");
const std::string RemoteSyslogListener::PROP_THREADS("threads");
const std::string RemoteSyslogListener::LOG_PROP_APP("app");
const std::string RemoteSyslogListener::LOG_PROP_HOST("host");
const std::string RemoteSyslogListener::LOG_PROP_STRUCTURED_DATA("structured-data");
RemoteSyslogListener::RemoteSyslogListener():
_pListener(0),
_pParser(0),
_port(RemoteSyslogChannel::SYSLOG_PORT),
_threads(1)
{
}
RemoteSyslogListener::RemoteSyslogListener(Poco::UInt16 port):
_pListener(0),
_pParser(0),
_port(port),
_threads(1)
{
}
RemoteSyslogListener::RemoteSyslogListener(Poco::UInt16 port, int threads):
_pListener(0),
_pParser(0),
_port(port),
_threads(threads)
{
}
RemoteSyslogListener::~RemoteSyslogListener()
{
}
void RemoteSyslogListener::processMessage(const std::string& messageText)
{
Poco::Message message;
_pParser->parse(messageText, message);
log(message);
}
void RemoteSyslogListener::enqueueMessage(const std::string& messageText, const Poco::Net::SocketAddress& senderAddress)
{
_queue.enqueueNotification(new MessageNotification(messageText, senderAddress));
}
void RemoteSyslogListener::setProperty(const std::string& name, const std::string& value)
{
if (name == PROP_PORT)
{
int val = Poco::NumberParser::parse(value);
if (val >= 0 && val < 65536)
_port = static_cast<Poco::UInt16>(val);
else
throw Poco::InvalidArgumentException("Not a valid port number", value);
}
else if (name == PROP_THREADS)
{
int val = Poco::NumberParser::parse(value);
if (val > 0 && val < 16)
_threads = val;
else
throw Poco::InvalidArgumentException("Invalid number of threads", value);
}
else
{
SplitterChannel::setProperty(name, value);
}
}
std::string RemoteSyslogListener::getProperty(const std::string& name) const
{
if (name == PROP_PORT)
return Poco::NumberFormatter::format(_port);
else if (name == PROP_THREADS)
return Poco::NumberFormatter::format(_threads);
else
return SplitterChannel::getProperty(name);
}
void RemoteSyslogListener::open()
{
SplitterChannel::open();
_pParser = new SyslogParser(_queue, this);
if (_port > 0)
{
_pListener = new RemoteUDPListener(_queue, _port);
}
for (int i = 0; i < _threads; i++)
{
_threadPool.start(*_pParser);
}
if (_pListener)
{
_threadPool.start(*_pListener);
}
}
void RemoteSyslogListener::close()
{
if (_pListener)
{
_pListener->safeStop();
}
if (_pParser)
{
_pParser->safeStop();
}
_queue.clear();
_threadPool.joinAll();
delete _pListener;
delete _pParser;
_pListener = 0;
_pParser = 0;
SplitterChannel::close();
}
void RemoteSyslogListener::registerChannel()
{
Poco::LoggingFactory::defaultFactory().registerChannelClass("RemoteSyslogListener", new Poco::Instantiator<RemoteSyslogListener, Poco::Channel>);
}
} } // namespace Poco::Net
+210
View File
@@ -0,0 +1,210 @@
//
// SMTPChannel.cpp
//
// Library: Net
// Package: Logging
// Module: SMTPChannel
//
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/SMTPChannel.h"
#include "Poco/Net/MailMessage.h"
#include "Poco/Net/MailRecipient.h"
#include "Poco/Net/SMTPClientSession.h"
#include "Poco/Net/StringPartSource.h"
#include "Poco/Message.h"
#include "Poco/DateTimeFormatter.h"
#include "Poco/DateTimeFormat.h"
#include "Poco/LocalDateTime.h"
#include "Poco/LoggingFactory.h"
#include "Poco/Instantiator.h"
#include "Poco/NumberFormatter.h"
#include "Poco/FileStream.h"
#include "Poco/File.h"
#include "Poco/Environment.h"
namespace Poco {
namespace Net {
const std::string SMTPChannel::PROP_MAILHOST("mailhost");
const std::string SMTPChannel::PROP_SENDER("sender");
const std::string SMTPChannel::PROP_RECIPIENT("recipient");
const std::string SMTPChannel::PROP_LOCAL("local");
const std::string SMTPChannel::PROP_ATTACHMENT("attachment");
const std::string SMTPChannel::PROP_TYPE("type");
const std::string SMTPChannel::PROP_DELETE("delete");
const std::string SMTPChannel::PROP_THROW("throw");
SMTPChannel::SMTPChannel():
_mailHost("localhost"),
_local(true),
_type("text/plain"),
_delete(false),
_throw(false)
{
}
SMTPChannel::SMTPChannel(const std::string& mailhost, const std::string& sender, const std::string& recipient):
_mailHost(mailhost),
_sender(sender),
_recipient(recipient),
_local(true),
_type("text/plain"),
_delete(false),
_throw(false)
{
}
SMTPChannel::~SMTPChannel()
{
try
{
close();
}
catch (...)
{
poco_unexpected();
}
}
void SMTPChannel::open()
{
}
void SMTPChannel::close()
{
}
void SMTPChannel::log(const Message& msg)
{
try
{
MailMessage message;
message.setSender(_sender);
message.addRecipient(MailRecipient(MailRecipient::PRIMARY_RECIPIENT, _recipient));
message.setSubject("Log Message from " + _sender);
std::stringstream content;
content << "Log Message\r\n"
<< "===========\r\n\r\n"
<< "Host: " << Environment::nodeName() << "\r\n"
<< "Logger: " << msg.getSource() << "\r\n";
if (_local)
{
DateTime dt(msg.getTime());
content << "Timestamp: " << DateTimeFormatter::format(LocalDateTime(dt), DateTimeFormat::RFC822_FORMAT) << "\r\n";
}
else
content << "Timestamp: " << DateTimeFormatter::format(msg.getTime(), DateTimeFormat::RFC822_FORMAT) << "\r\n";
content << "Priority: " << NumberFormatter::format(msg.getPriority()) << "\r\n"
<< "Process ID: " << NumberFormatter::format(msg.getPid()) << "\r\n"
<< "Thread: " << msg.getThread() << " (ID: " << msg.getTid() << ")\r\n"
<< "Message text: " << msg.getText() << "\r\n\r\n";
message.addContent(new StringPartSource(content.str()));
if (!_attachment.empty())
{
{
Poco::FileInputStream fis(_attachment, std::ios::in | std::ios::binary | std::ios::ate);
if (fis.good())
{
typedef std::allocator<std::string::value_type>::size_type SST;
std::streamoff size = fis.tellg();
poco_assert (std::numeric_limits<unsigned int>::max() >= size);
poco_assert (std::numeric_limits<SST>::max() >= size);
char* pMem = new char [static_cast<unsigned int>(size)];
fis.seekg(std::ios::beg);
fis.read(pMem, size);
message.addAttachment(_attachment,
new StringPartSource(std::string(pMem, static_cast<SST>(size)),
_type,
_attachment));
delete [] pMem;
}
}
if (_delete) File(_attachment).remove();
}
SMTPClientSession session(_mailHost);
session.login();
session.sendMessage(message);
session.close();
}
catch (Exception&)
{
if (_throw) throw;
}
}
void SMTPChannel::setProperty(const std::string& name, const std::string& value)
{
if (name == PROP_MAILHOST)
_mailHost = value;
else if (name == PROP_SENDER)
_sender = value;
else if (name == PROP_RECIPIENT)
_recipient = value;
else if (name == PROP_LOCAL)
_local = isTrue(value);
else if (name == PROP_ATTACHMENT)
_attachment = value;
else if (name == PROP_TYPE)
_type = value;
else if (name == PROP_DELETE)
_delete = isTrue(value);
else if (name == PROP_THROW)
_throw = isTrue(value);
else
Channel::setProperty(name, value);
}
std::string SMTPChannel::getProperty(const std::string& name) const
{
if (name == PROP_MAILHOST)
return _mailHost;
else if (name == PROP_SENDER)
return _sender;
else if (name == PROP_RECIPIENT)
return _recipient;
else if (name == PROP_LOCAL)
return _local ? "true" : "false";
else if (name == PROP_ATTACHMENT)
return _attachment;
else if (name == PROP_TYPE)
return _type;
else if (name == PROP_DELETE)
return _delete ? "true" : "false";
else if (name == PROP_THROW)
return _throw ? "true" : "false";
else
return Channel::getProperty(name);
}
void SMTPChannel::registerChannel()
{
Poco::LoggingFactory::defaultFactory().registerChannelClass("SMTPChannel",
new Poco::Instantiator<SMTPChannel, Poco::Channel>);
}
} } // namespace Poco::Net
+543
View File
@@ -0,0 +1,543 @@
//
// SMTPClientSession.cpp
//
// Library: Net
// Package: Mail
// Module: SMTPClientSession
//
// Copyright (c) 2005-2008, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/SMTPClientSession.h"
#include "Poco/Net/MailMessage.h"
#include "Poco/Net/MailRecipient.h"
#include "Poco/Net/MailStream.h"
#include "Poco/Net/SocketAddress.h"
#include "Poco/Net/SocketStream.h"
#include "Poco/Net/NetException.h"
#include "Poco/Net/NetworkInterface.h"
#include "Poco/Net/NTLMCredentials.h"
#include "Poco/Net/SSPINTLMCredentials.h"
#include "Poco/Environment.h"
#include "Poco/HMACEngine.h"
#include "Poco/MD5Engine.h"
#include "Poco/SHA1Engine.h"
#include "Poco/DigestStream.h"
#include "Poco/StreamCopier.h"
#include "Poco/Base64Encoder.h"
#include "Poco/Base64Decoder.h"
#include "Poco/String.h"
#include <sstream>
#include <fstream>
#include <iostream>
using Poco::DigestEngine;
using Poco::HMACEngine;
using Poco::MD5Engine;
using Poco::SHA1Engine;
using Poco::DigestOutputStream;
using Poco::StreamCopier;
using Poco::Base64Encoder;
using Poco::Base64Decoder;
using Poco::Environment;
namespace Poco {
namespace Net {
SMTPClientSession::SMTPClientSession(const StreamSocket& socket):
_socket(socket),
_isOpen(false)
{
}
SMTPClientSession::SMTPClientSession(const std::string& host, Poco::UInt16 port):
_host(host),
_socket(SocketAddress(host, port)),
_isOpen(false)
{
}
SMTPClientSession::~SMTPClientSession()
{
try
{
close();
}
catch (...)
{
}
}
void SMTPClientSession::setTimeout(const Poco::Timespan& timeout)
{
_socket.setReceiveTimeout(timeout);
}
Poco::Timespan SMTPClientSession::getTimeout() const
{
return _socket.getReceiveTimeout();
}
void SMTPClientSession::login(const std::string& hostname, std::string& response)
{
open();
int status = sendCommand("EHLO", hostname, response);
if (isPermanentNegative(status))
status = sendCommand("HELO", hostname, response);
if (!isPositiveCompletion(status)) throw SMTPException("Login failed", response, status);
}
void SMTPClientSession::login(const std::string& hostname)
{
std::string response;
login(hostname, response);
}
void SMTPClientSession::login()
{
login(Environment::nodeName());
}
void SMTPClientSession::loginUsingCRAMMD5(const std::string& username, const std::string& password)
{
HMACEngine<MD5Engine> hmac(password);
loginUsingCRAM(username, "CRAM-MD5", hmac);
}
void SMTPClientSession::loginUsingCRAMSHA1(const std::string& username, const std::string& password)
{
HMACEngine<SHA1Engine> hmac(password);
loginUsingCRAM(username, "CRAM-SHA1", hmac);
}
void SMTPClientSession::loginUsingCRAM(const std::string& username, const std::string& method, Poco::DigestEngine& hmac)
{
std::string response;
int status = sendCommand(std::string("AUTH ") + method, response);
if (!isPositiveIntermediate(status)) throw SMTPException(std::string("Cannot authenticate using ") + method, response, status);
std::string challengeBase64 = response.substr(4);
std::istringstream istr(challengeBase64);
Base64Decoder decoder(istr);
std::string challenge;
StreamCopier::copyToString(decoder, challenge);
hmac.update(challenge);
const DigestEngine::Digest& digest = hmac.digest();
std::string digestString(DigestEngine::digestToHex(digest));
std::string challengeResponse = username + " " + digestString;
std::ostringstream challengeResponseBase64;
Base64Encoder encoder(challengeResponseBase64);
encoder.rdbuf()->setLineLength(0);
encoder << challengeResponse;
encoder.close();
status = sendCommand(challengeResponseBase64.str(), response);
if (!isPositiveCompletion(status)) throw SMTPException(std::string("Login using ") + method + " failed", response, status);
}
void SMTPClientSession::loginUsingLogin(const std::string& username, const std::string& password)
{
std::string response;
int status = sendCommand("AUTH LOGIN", response);
if (!isPositiveIntermediate(status)) throw SMTPException("Cannot authenticate using LOGIN", response, status);
std::ostringstream usernameBase64;
Base64Encoder usernameEncoder(usernameBase64);
usernameEncoder.rdbuf()->setLineLength(0);
usernameEncoder << username;
usernameEncoder.close();
std::ostringstream passwordBase64;
Base64Encoder passwordEncoder(passwordBase64);
passwordEncoder.rdbuf()->setLineLength(0);
passwordEncoder << password;
passwordEncoder.close();
//Server request for username/password not defined could be either
//S: login:
//C: user_login
//S: password:
//C: user_password
//or
//S: password:
//C: user_password
//S: login:
//C: user_login
std::string decodedResponse;
std::istringstream responseStream(response.substr(4));
Base64Decoder responseDecoder(responseStream);
StreamCopier::copyToString(responseDecoder, decodedResponse);
if (Poco::icompare(decodedResponse, 0, 8, "username") == 0) // username first (md5("Username:"))
{
status = sendCommand(usernameBase64.str(), response);
if (!isPositiveIntermediate(status)) throw SMTPException("Login using LOGIN username failed", response, status);
status = sendCommand(passwordBase64.str(), response);
if (!isPositiveCompletion(status)) throw SMTPException("Login using LOGIN password failed", response, status);
}
else if (Poco::icompare(decodedResponse, 0, 8, "password") == 0) // password first (md5("Password:"))
{
status = sendCommand(passwordBase64.str(), response);
if (!isPositiveIntermediate(status)) throw SMTPException("Login using LOGIN password failed", response, status);
status = sendCommand(usernameBase64.str(), response);
if (!isPositiveCompletion(status)) throw SMTPException("Login using LOGIN username failed", response, status);
}
}
void SMTPClientSession::loginUsingPlain(const std::string& username, const std::string& password)
{
std::ostringstream credentialsBase64;
Base64Encoder credentialsEncoder(credentialsBase64);
credentialsEncoder.rdbuf()->setLineLength(0);
credentialsEncoder << '\0' << username << '\0' << password;
credentialsEncoder.close();
std::string response;
int status = sendCommand("AUTH PLAIN", credentialsBase64.str(), response);
if (!isPositiveCompletion(status)) throw SMTPException("Login using PLAIN failed", response, status);
}
void SMTPClientSession::loginUsingXOAUTH2(const std::string& username, const std::string& password)
{
std::ostringstream credentialsBase64;
Base64Encoder credentialsEncoder(credentialsBase64);
credentialsEncoder.rdbuf()->setLineLength(0);
credentialsEncoder << "user=" << username << "\001auth=Bearer " << password << "\001\001";
credentialsEncoder.close();
std::string response;
int status = sendCommand("AUTH XOAUTH2", credentialsBase64.str(), response);
if (!isPositiveCompletion(status)) throw SMTPException("Login using XOAUTH2 failed", response, status);
}
void SMTPClientSession::loginUsingNTLM(const std::string& username, const std::string& password)
{
// Implementation is based on:
// [MS-SMTPNTLM]: NT LAN Manager (NTLM) Authentication: Simple Mail Transfer Protocol (SMTP) Extension
// https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smtpntlm/50c668f6-5ffc-4616-96df-b5a3f4b3311d
std::string user;
std::string domain;
std::vector<unsigned char> negotiateBuf;
Poco::SharedPtr<NTLMContext> pNTLMContext;
if (username.empty() && password.empty() && !_host.empty() && SSPINTLMCredentials::available())
{
pNTLMContext = SSPINTLMCredentials::createNTLMContext(_host, SSPINTLMCredentials::SERVICE_SMTP);
negotiateBuf = SSPINTLMCredentials::negotiate(*pNTLMContext);
}
else
{
NTLMCredentials::NegotiateMessage negotiateMsg;
NTLMCredentials::splitUsername(username, user, domain);
negotiateMsg.domain = domain;
negotiateBuf = NTLMCredentials::formatNegotiateMessage(negotiateMsg);
}
std::string response;
int status = sendCommand("AUTH NTLM", NTLMCredentials::toBase64(negotiateBuf), response);
if (status == 334)
{
std::vector<unsigned char> authenticateBuf;
std::vector<unsigned char> buffer = NTLMCredentials::fromBase64(response.substr(4));
if (buffer.empty()) throw SMTPException("Invalid NTLM challenge");
if (pNTLMContext)
{
authenticateBuf = SSPINTLMCredentials::authenticate(*pNTLMContext, buffer);
}
else
{
NTLMCredentials::ChallengeMessage challengeMsg;
if (NTLMCredentials::parseChallengeMessage(&buffer[0], buffer.size(), challengeMsg))
{
if ((challengeMsg.flags & NTLMCredentials::NTLM_FLAG_NEGOTIATE_NTLM2_KEY) == 0)
{
throw SMTPException("Server does not support NTLMv2 authentication");
}
NTLMCredentials::AuthenticateMessage authenticateMsg;
authenticateMsg.flags = challengeMsg.flags;
authenticateMsg.target = challengeMsg.target;
authenticateMsg.username = user;
std::vector<unsigned char> lmNonce = NTLMCredentials::createNonce();
std::vector<unsigned char> ntlmNonce = NTLMCredentials::createNonce();
Poco::UInt64 timestamp = NTLMCredentials::createTimestamp();
std::vector<unsigned char> ntlm2Hash = NTLMCredentials::createNTLMv2Hash(user, challengeMsg.target, password);
authenticateMsg.lmResponse = NTLMCredentials::createLMv2Response(ntlm2Hash, challengeMsg.challenge, lmNonce);
authenticateMsg.ntlmResponse = NTLMCredentials::createNTLMv2Response(ntlm2Hash, challengeMsg.challenge, ntlmNonce, challengeMsg.targetInfo, timestamp);
authenticateBuf = NTLMCredentials::formatAuthenticateMessage(authenticateMsg);
}
else throw SMTPException("Invalid NTLM challenge");
}
status = sendCommand(NTLMCredentials::toBase64(authenticateBuf), response);
if (status != 235) throw SMTPException("NTLM authentication failed", response, status);
}
else throw SMTPException("Server does not support NTLM authentication");
}
void SMTPClientSession::login(LoginMethod loginMethod, const std::string& username, const std::string& password)
{
login(Environment::nodeName(), loginMethod, username, password);
}
void SMTPClientSession::login(const std::string& hostname, LoginMethod loginMethod, const std::string& username, const std::string& password)
{
std::string response;
login(hostname, response);
if (loginMethod == AUTH_CRAM_MD5)
{
if (response.find("CRAM-MD5", 0) != std::string::npos)
{
loginUsingCRAMMD5(username, password);
}
else throw SMTPException("The mail service does not support CRAM-MD5 authentication", response);
}
else if (loginMethod == AUTH_CRAM_SHA1)
{
if (response.find("CRAM-SHA1", 0) != std::string::npos)
{
loginUsingCRAMSHA1(username, password);
}
else throw SMTPException("The mail service does not support CRAM-SHA1 authentication", response);
}
else if (loginMethod == AUTH_LOGIN)
{
if (response.find("LOGIN", 0) != std::string::npos)
{
loginUsingLogin(username, password);
}
else throw SMTPException("The mail service does not support LOGIN authentication", response);
}
else if (loginMethod == AUTH_PLAIN)
{
if (response.find("PLAIN", 0) != std::string::npos)
{
loginUsingPlain(username, password);
}
else throw SMTPException("The mail service does not support PLAIN authentication", response);
}
else if (loginMethod == AUTH_XOAUTH2)
{
if (response.find("XOAUTH2", 0) != std::string::npos)
{
loginUsingXOAUTH2(username, password);
}
else throw SMTPException("The mail service does not support XOAUTH2 authentication", response);
}
else if (loginMethod == AUTH_NTLM)
{
if (response.find("NTLM", 0) != std::string::npos)
{
loginUsingNTLM(username, password);
}
else throw SMTPException("The mail service does not support NTLM authentication", response);
}
else if (loginMethod != AUTH_NONE)
{
throw SMTPException("The autentication method is not supported");
}
}
void SMTPClientSession::open()
{
if (!_isOpen)
{
std::string response;
int status = _socket.receiveStatusMessage(response);
if (!isPositiveCompletion(status)) throw SMTPException("The mail service is unavailable", response, status);
_isOpen = true;
}
}
void SMTPClientSession::close()
{
if (_isOpen)
{
std::string response;
sendCommand("QUIT", response);
_socket.close();
_isOpen = false;
}
}
void SMTPClientSession::sendCommands(const MailMessage& message, const Recipients* pRecipients)
{
std::string response;
int status = 0;
const std::string& fromField = message.getSender();
std::string::size_type emailPos = fromField.find('<');
if (emailPos == std::string::npos)
{
std::string sender("<");
sender.append(fromField);
sender.append(">");
status = sendCommand("MAIL FROM:", sender, response);
}
else
{
status = sendCommand("MAIL FROM:", fromField.substr(emailPos, fromField.size() - emailPos), response);
}
if (!isPositiveCompletion(status)) throw SMTPException("Cannot send message", response, status);
std::ostringstream recipient;
if (pRecipients)
{
for (const auto& rec: *pRecipients)
{
recipient << '<' << rec << '>';
int status = sendCommand("RCPT TO:", recipient.str(), response);
if (!isPositiveCompletion(status)) throw SMTPException(std::string("Recipient rejected: ") + recipient.str(), response, status);
recipient.str("");
}
}
else
{
for (const auto& rec: message.recipients())
{
recipient << '<' << rec.getAddress() << '>';
int status = sendCommand("RCPT TO:", recipient.str(), response);
if (!isPositiveCompletion(status)) throw SMTPException(std::string("Recipient rejected: ") + recipient.str(), response, status);
recipient.str("");
}
}
status = sendCommand("DATA", response);
if (!isPositiveIntermediate(status)) throw SMTPException("Cannot send message data", response, status);
}
void SMTPClientSession::sendAddresses(const std::string& from, const Recipients& recipients)
{
std::string response;
int status = 0;
std::string::size_type emailPos = from.find('<');
if (emailPos == std::string::npos)
{
std::string sender("<");
sender.append(from);
sender.append(">");
status = sendCommand("MAIL FROM:", sender, response);
}
else
{
status = sendCommand("MAIL FROM:", from.substr(emailPos, from.size() - emailPos), response);
}
if (!isPositiveCompletion(status)) throw SMTPException("Cannot send message", response, status);
std::ostringstream recipient;
for (const auto& rec: recipients)
{
recipient << '<' << rec << '>';
int status = sendCommand("RCPT TO:", recipient.str(), response);
if (!isPositiveCompletion(status)) throw SMTPException(std::string("Recipient rejected: ") + recipient.str(), response, status);
recipient.str("");
}
}
void SMTPClientSession::sendData()
{
std::string response;
int status = sendCommand("DATA", response);
if (!isPositiveIntermediate(status)) throw SMTPException("Cannot send message data", response, status);
}
void SMTPClientSession::sendMessage(const MailMessage& message)
{
sendCommands(message);
transportMessage(message);
}
void SMTPClientSession::sendMessage(const MailMessage& message, const Recipients& recipients)
{
sendCommands(message, &recipients);
transportMessage(message);
}
void SMTPClientSession::transportMessage(const MailMessage& message)
{
SocketOutputStream socketStream(_socket);
MailOutputStream mailStream(socketStream);
message.write(mailStream);
mailStream.close();
socketStream.flush();
std::string response;
int status = _socket.receiveStatusMessage(response);
if (!isPositiveCompletion(status)) throw SMTPException("The server rejected the message", response, status);
}
int SMTPClientSession::sendCommand(const std::string& command, std::string& response)
{
_socket.sendMessage(command);
return _socket.receiveStatusMessage(response);
}
int SMTPClientSession::sendCommand(const std::string& command, const std::string& arg, std::string& response)
{
_socket.sendMessage(command, arg);
return _socket.receiveStatusMessage(response);
}
void SMTPClientSession::sendMessage(std::istream& istr)
{
std::string response;
int status = 0;
SocketOutputStream socketStream(_socket);
MailOutputStream mailStream(socketStream);
StreamCopier::copyStream(istr, mailStream);
mailStream.close();
socketStream.flush();
status = _socket.receiveStatusMessage(response);
if (!isPositiveCompletion(status)) throw SMTPException("The server rejected the message", response, status);
}
} } // namespace Poco::Net
+318
View File
@@ -0,0 +1,318 @@
//
// SSPINTLMCredentials.cpp
//
// Library: Net
// Package: NTLM
// Module: SSPINTLMCredentials
//
// Copyright (c) 2019, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/SSPINTLMCredentials.h"
#if POCO_OS == POCO_OS_WINDOWS_NT
#include "Poco/SharedLibrary.h"
#include "Poco/SingletonHolder.h"
#include "Poco/UnicodeConverter.h"
#include <vector>
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#define SECURITY_WIN32
#include <security.h>
namespace Poco {
namespace Net {
struct NTLMContextImpl
{
NTLMContextImpl():
maxTokenSize(0)
{
SecInvalidateHandle(&credentials);
SecInvalidateHandle(&context);
}
std::size_t maxTokenSize;
CredHandle credentials;
CtxtHandle context;
std::wstring spn;
};
class SSPINTLMProvider
{
public:
SSPINTLMProvider():
_securityLib("security.dll"),
_pSecFunTable(0)
{
InitSecurityInterfaceW pInitSecurityInterface = reinterpret_cast<InitSecurityInterfaceW>(_securityLib.getSymbol("InitSecurityInterfaceW"));
if (pInitSecurityInterface)
{
_pSecFunTable = pInitSecurityInterface();
}
if (!_pSecFunTable) throw Poco::SystemException("Failed to initialize SSPI");
}
~SSPINTLMProvider()
{
}
bool available()
{
PSecPkgInfoW pSecPkgInfo;
SECURITY_STATUS status = _pSecFunTable->QuerySecurityPackageInfoW(L"NTLM", &pSecPkgInfo);
if (status == SEC_E_OK)
{
_pSecFunTable->FreeContextBuffer(pSecPkgInfo);
return true;
}
else return false;
}
Poco::SharedPtr<NTLMContext> createNTLMContext(const std::string& host, const std::string& service)
{
PSecPkgInfoW pSecPkgInfo;
SECURITY_STATUS status = _pSecFunTable->QuerySecurityPackageInfoW(L"NTLM", &pSecPkgInfo);
if (status != SEC_E_OK) throw Poco::SystemException("NTLM SSPI not available", status);
std::size_t maxTokenSize = pSecPkgInfo->cbMaxToken;
_pSecFunTable->FreeContextBuffer(pSecPkgInfo);
Poco::SharedPtr<NTLMContext> pContext = new NTLMContext(new NTLMContextImpl);
pContext->_pImpl->maxTokenSize = maxTokenSize;
TimeStamp expiry;
status = _pSecFunTable->AcquireCredentialsHandleW(
NULL,
L"NTLM",
SECPKG_CRED_OUTBOUND,
NULL,
NULL,
NULL,
NULL,
&pContext->_pImpl->credentials,
&expiry);
if (status != SEC_E_OK) throw Poco::SystemException("Failed to acquire NTLM credentials", status);
std::string spn = service;
spn += '/';
spn += host;
Poco::UnicodeConverter::convert(spn, pContext->_pImpl->spn);
return pContext;
}
std::vector<unsigned char> negotiate(NTLMContext& context)
{
std::vector<unsigned char> buffer(context._pImpl->maxTokenSize);
SecBuffer msgBuffer;
msgBuffer.BufferType = SECBUFFER_TOKEN;
msgBuffer.pvBuffer = &buffer[0];
msgBuffer.cbBuffer = static_cast<unsigned long>(buffer.size());
SecBufferDesc msgBufferDesc;
msgBufferDesc.ulVersion = SECBUFFER_VERSION;
msgBufferDesc.cBuffers = 1;
msgBufferDesc.pBuffers = &msgBuffer;
unsigned long attrs;
TimeStamp expiry;
SECURITY_STATUS status = _pSecFunTable->InitializeSecurityContextW(
&context._pImpl->credentials,
NULL,
const_cast<SEC_WCHAR*>(context._pImpl->spn.c_str()),
0,
0,
SECURITY_NETWORK_DREP,
NULL,
0,
&context._pImpl->context,
&msgBufferDesc,
&attrs,
&expiry);
if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE)
{
_pSecFunTable->CompleteAuthToken(&context._pImpl->context, &msgBufferDesc);
}
else if (status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED)
{
throw Poco::SystemException("Failed to initialize NTLM security context", status);
}
buffer.resize(msgBuffer.cbBuffer);
return buffer;
}
std::vector<unsigned char> authenticate(NTLMContext& context, const std::vector<unsigned char>& challenge)
{
std::vector<unsigned char> response(context._pImpl->maxTokenSize);
SecBuffer responseBuffer;
responseBuffer.BufferType = SECBUFFER_TOKEN;
responseBuffer.pvBuffer = &response[0];
responseBuffer.cbBuffer = static_cast<unsigned long>(response.size());
SecBufferDesc responseBufferDesc;
responseBufferDesc.ulVersion = SECBUFFER_VERSION;
responseBufferDesc.cBuffers = 1;
responseBufferDesc.pBuffers = &responseBuffer;
SecBuffer challengeBuffer;
challengeBuffer.BufferType = SECBUFFER_TOKEN;
challengeBuffer.pvBuffer = const_cast<unsigned char*>(&challenge[0]);
challengeBuffer.cbBuffer = static_cast<unsigned long>(challenge.size());
SecBufferDesc challengeBufferDesc;
challengeBufferDesc.ulVersion = SECBUFFER_VERSION;
challengeBufferDesc.cBuffers = 1;
challengeBufferDesc.pBuffers = &challengeBuffer;
unsigned long attrs;
TimeStamp expiry;
SECURITY_STATUS status = _pSecFunTable->InitializeSecurityContextW(
&context._pImpl->credentials,
&context._pImpl->context,
const_cast<SEC_WCHAR*>(context._pImpl->spn.c_str()),
0,
0,
SECURITY_NETWORK_DREP,
&challengeBufferDesc,
0,
&context._pImpl->context,
&responseBufferDesc,
&attrs,
&expiry);
if (status != SEC_E_OK)
{
throw Poco::SystemException("Failed to create NTLM authenticate message", status);
}
response.resize(responseBuffer.cbBuffer);
return response;
}
void clearNTLMContext(NTLMContext& ctx)
{
if (SecIsValidHandle(&ctx._pImpl->context))
{
_pSecFunTable->DeleteSecurityContext(&ctx._pImpl->context);
}
if (SecIsValidHandle(&ctx._pImpl->credentials))
{
_pSecFunTable->FreeCredentialsHandle(&ctx._pImpl->credentials);
}
}
static SSPINTLMProvider& instance();
private:
typedef PSecurityFunctionTableW(APIENTRY *InitSecurityInterfaceW)(VOID);
Poco::SharedLibrary _securityLib;
PSecurityFunctionTableW _pSecFunTable;
};
namespace
{
static Poco::SingletonHolder<SSPINTLMProvider> sspintlmProviderHolder;
}
SSPINTLMProvider& SSPINTLMProvider::instance()
{
return *sspintlmProviderHolder.get();
}
} } // namespace Poco::Net
#endif // POCO_OS == POCO_OS_WINDOWS_NT
namespace Poco {
namespace Net {
const std::string SSPINTLMCredentials::SERVICE_HTTP("HTTP");
const std::string SSPINTLMCredentials::SERVICE_SMTP("SMTP");
NTLMContext::NTLMContext(NTLMContextImpl* pImpl):
_pImpl(pImpl)
{
}
NTLMContext::~NTLMContext()
{
#if POCO_OS == POCO_OS_WINDOWS_NT
SSPINTLMProvider::instance().clearNTLMContext(*this);
delete _pImpl;
#endif
}
bool SSPINTLMCredentials::available()
{
#if POCO_OS == POCO_OS_WINDOWS_NT
try
{
return SSPINTLMProvider::instance().available();
}
catch (...)
{
return false;
}
#else
return false;
#endif
}
Poco::SharedPtr<NTLMContext> SSPINTLMCredentials::createNTLMContext(const std::string& workstation, const std::string& service)
{
#if POCO_OS == POCO_OS_WINDOWS_NT
return SSPINTLMProvider::instance().createNTLMContext(workstation, service);
#else
throw Poco::NotImplementedException("SSPINTLMCredentials::createNTLMContext() is only available on Windows");
#endif
}
std::vector<unsigned char> SSPINTLMCredentials::negotiate(NTLMContext& context)
{
#if POCO_OS == POCO_OS_WINDOWS_NT
return SSPINTLMProvider::instance().negotiate(context);
#else
throw Poco::NotImplementedException("SSPINTLMCredentials::negotiate() is only available on Windows");
#endif
}
std::vector<unsigned char> SSPINTLMCredentials::authenticate(NTLMContext& context, const std::vector<unsigned char>& challenge)
{
#if POCO_OS == POCO_OS_WINDOWS_NT
return SSPINTLMProvider::instance().authenticate(context, challenge);
#else
throw Poco::NotImplementedException("SSPINTLMCredentials::authenticate() is only available on Windows");
#endif
}
} } // namespace Poco::Net
+158
View File
@@ -0,0 +1,158 @@
//
// ServerSocket.cpp
//
// Library: Net
// Package: Sockets
// Module: ServerSocket
//
// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/ServerSocket.h"
#include "Poco/Net/ServerSocketImpl.h"
#include "Poco/Exception.h"
using Poco::InvalidArgumentException;
namespace Poco {
namespace Net {
ServerSocket::ServerSocket(): Socket(new ServerSocketImpl)
{
}
ServerSocket::ServerSocket(const Socket& socket): Socket(socket)
{
if (!dynamic_cast<ServerSocketImpl*>(impl()))
throw InvalidArgumentException("Cannot assign incompatible socket");
}
ServerSocket::ServerSocket(const SocketAddress& address, int backlog): Socket(new ServerSocketImpl)
{
impl()->bind(address, true);
impl()->listen(backlog);
}
ServerSocket::ServerSocket(Poco::UInt16 port, int backlog): Socket(new ServerSocketImpl)
{
IPAddress wildcardAddr;
SocketAddress address(wildcardAddr, port);
impl()->bind(address, true);
impl()->listen(backlog);
}
ServerSocket::ServerSocket(SocketImpl* pImpl, bool ignore): Socket(pImpl)
{
}
ServerSocket::~ServerSocket()
{
}
ServerSocket& ServerSocket::operator = (const Socket& socket)
{
if (dynamic_cast<ServerSocketImpl*>(socket.impl()))
Socket::operator = (socket);
else
throw InvalidArgumentException("Cannot assign incompatible socket");
return *this;
}
void ServerSocket::bind(const SocketAddress& address, bool reuseAddress)
{
impl()->bind(address, reuseAddress);
}
void ServerSocket::bind(const SocketAddress& address, bool reuseAddress, bool reusePort)
{
impl()->bind(address, reuseAddress, reusePort);
}
void ServerSocket::bind(Poco::UInt16 port, bool reuseAddress)
{
IPAddress wildcardAddr;
SocketAddress address(wildcardAddr, port);
impl()->bind(address, reuseAddress);
}
void ServerSocket::bind(Poco::UInt16 port, bool reuseAddress, bool reusePort)
{
IPAddress wildcardAddr;
SocketAddress address(wildcardAddr, port);
impl()->bind(address, reuseAddress, reusePort);
}
void ServerSocket::bind6(const SocketAddress& address, bool reuseAddress, bool ipV6Only)
{
impl()->bind6(address, reuseAddress, ipV6Only);
}
void ServerSocket::bind6(const SocketAddress& address, bool reuseAddress, bool reusePort, bool ipV6Only)
{
impl()->bind6(address, reuseAddress, reusePort, ipV6Only);
}
void ServerSocket::bind6(Poco::UInt16 port, bool reuseAddress, bool ipV6Only)
{
#if defined(POCO_HAVE_IPv6)
IPAddress wildcardAddr(IPAddress::IPv6);
SocketAddress address(wildcardAddr, port);
impl()->bind6(address, reuseAddress, ipV6Only);
#else
throw Poco::NotImplementedException("No IPv6 support available");
#endif // POCO_HAVE_IPv6
}
void ServerSocket::bind6(Poco::UInt16 port, bool reuseAddress, bool reusePort, bool ipV6Only)
{
#if defined(POCO_HAVE_IPv6)
IPAddress wildcardAddr(IPAddress::IPv6);
SocketAddress address(wildcardAddr, port);
impl()->bind6(address, reuseAddress, reusePort, ipV6Only);
#else
throw Poco::NotImplementedException("No IPv6 support available");
#endif // POCO_HAVE_IPv6
}
void ServerSocket::listen(int backlog)
{
impl()->listen(backlog);
}
StreamSocket ServerSocket::acceptConnection(SocketAddress& clientAddr)
{
return StreamSocket(impl()->acceptConnection(clientAddr));
}
StreamSocket ServerSocket::acceptConnection()
{
SocketAddress clientAddr;
return StreamSocket(impl()->acceptConnection(clientAddr));
}
} } // namespace Poco::Net
+32
View File
@@ -0,0 +1,32 @@
//
// ServerSocketImpl.cpp
//
// Library: Net
// Package: Sockets
// Module: ServerSocketImpl
//
// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/ServerSocketImpl.h"
namespace Poco {
namespace Net {
ServerSocketImpl::ServerSocketImpl()
{
}
ServerSocketImpl::~ServerSocketImpl()
{
}
} } // namespace Poco::Net
+467
View File
@@ -0,0 +1,467 @@
//
// Socket.cpp
//
// Library: Net
// Package: Sockets
// Module: Socket
//
// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/Socket.h"
#include "Poco/Net/StreamSocketImpl.h"
#include "Poco/Timestamp.h"
#include <algorithm>
#include <string.h> // FD_SET needs memset on some platforms, so we can't use <cstring>
#if defined(POCO_HAVE_FD_EPOLL)
#include <sys/epoll.h>
#elif defined(POCO_HAVE_FD_POLL)
#include "Poco/SharedPtr.h"
#include <poll.h>
#endif
namespace Poco {
namespace Net {
Socket::Socket():
_pImpl(new StreamSocketImpl)
{
}
Socket::Socket(SocketImpl* pImpl):
_pImpl(pImpl)
{
poco_check_ptr (_pImpl);
}
Socket::Socket(const Socket& socket):
_pImpl(socket._pImpl)
{
poco_check_ptr (_pImpl);
_pImpl->duplicate();
}
Socket& Socket::operator = (const Socket& socket)
{
if (&socket != this)
{
if (_pImpl) _pImpl->release();
_pImpl = socket._pImpl;
if (_pImpl) _pImpl->duplicate();
}
return *this;
}
Socket::~Socket()
{
_pImpl->release();
}
int Socket::select(SocketList& readList, SocketList& writeList, SocketList& exceptList, const Poco::Timespan& timeout)
{
#if defined(POCO_HAVE_FD_EPOLL)
int epollSize = readList.size() + writeList.size() + exceptList.size();
if (epollSize == 0) return 0;
int epollfd = -1;
{
struct epoll_event eventsIn[epollSize];
memset(eventsIn, 0, sizeof(eventsIn));
struct epoll_event* eventLast = eventsIn;
for (SocketList::iterator it = readList.begin(); it != readList.end(); ++it)
{
poco_socket_t sockfd = it->sockfd();
if (sockfd != POCO_INVALID_SOCKET)
{
struct epoll_event* e = eventsIn;
for (; e != eventLast; ++e)
{
if (reinterpret_cast<Socket*>(e->data.ptr)->sockfd() == sockfd)
break;
}
if (e == eventLast)
{
e->data.ptr = &(*it);
++eventLast;
}
e->events |= EPOLLIN;
}
}
for (SocketList::iterator it = writeList.begin(); it != writeList.end(); ++it)
{
poco_socket_t sockfd = it->sockfd();
if (sockfd != POCO_INVALID_SOCKET)
{
struct epoll_event* e = eventsIn;
for (; e != eventLast; ++e)
{
if (reinterpret_cast<Socket*>(e->data.ptr)->sockfd() == sockfd)
break;
}
if (e == eventLast)
{
e->data.ptr = &(*it);
++eventLast;
}
e->events |= EPOLLOUT;
}
}
for (SocketList::iterator it = exceptList.begin(); it != exceptList.end(); ++it)
{
poco_socket_t sockfd = it->sockfd();
if (sockfd != POCO_INVALID_SOCKET)
{
struct epoll_event* e = eventsIn;
for (; e != eventLast; ++e)
{
if (reinterpret_cast<Socket*>(e->data.ptr)->sockfd() == sockfd)
break;
}
if (e == eventLast)
{
e->data.ptr = &(*it);
++eventLast;
}
e->events |= EPOLLERR;
}
}
epollSize = eventLast - eventsIn;
if (epollSize == 0) return 0;
epollfd = epoll_create(1);
if (epollfd < 0)
{
SocketImpl::error("Can't create epoll queue");
}
for (struct epoll_event* e = eventsIn; e != eventLast; ++e)
{
poco_socket_t sockfd = reinterpret_cast<Socket*>(e->data.ptr)->sockfd();
if (sockfd != POCO_INVALID_SOCKET)
{
if (epoll_ctl(epollfd, EPOLL_CTL_ADD, sockfd, e) < 0)
{
::close(epollfd);
SocketImpl::error("Can't insert socket to epoll queue");
}
}
}
}
struct epoll_event eventsOut[epollSize];
memset(eventsOut, 0, sizeof(eventsOut));
Poco::Timespan remainingTime(timeout);
int rc;
do
{
Poco::Timestamp start;
rc = epoll_wait(epollfd, eventsOut, epollSize, remainingTime.totalMilliseconds());
if (rc < 0 && SocketImpl::lastError() == POCO_EINTR)
{
Poco::Timestamp end;
Poco::Timespan waited = end - start;
if (waited < remainingTime)
remainingTime -= waited;
else
remainingTime = 0;
}
}
while (rc < 0 && SocketImpl::lastError() == POCO_EINTR);
::close(epollfd);
if (rc < 0) SocketImpl::error();
SocketList readyReadList;
SocketList readyWriteList;
SocketList readyExceptList;
for (int n = 0; n < rc; ++n)
{
if (eventsOut[n].events & EPOLLERR)
readyExceptList.push_back(*reinterpret_cast<Socket*>(eventsOut[n].data.ptr));
if (eventsOut[n].events & EPOLLIN)
readyReadList.push_back(*reinterpret_cast<Socket*>(eventsOut[n].data.ptr));
if (eventsOut[n].events & EPOLLOUT)
readyWriteList.push_back(*reinterpret_cast<Socket*>(eventsOut[n].data.ptr));
}
std::swap(readList, readyReadList);
std::swap(writeList, readyWriteList);
std::swap(exceptList, readyExceptList);
return readList.size() + writeList.size() + exceptList.size();
#elif defined(POCO_HAVE_FD_POLL)
typedef Poco::SharedPtr<pollfd, Poco::ReferenceCounter, Poco::ReleaseArrayPolicy<pollfd>> SharedPollArray;
nfds_t nfd = readList.size() + writeList.size() + exceptList.size();
if (0 == nfd) return 0;
SharedPollArray pPollArr = new pollfd[nfd]();
int idx = 0;
for (SocketList::iterator it = readList.begin(); it != readList.end(); ++it)
{
pPollArr[idx].fd = int(it->sockfd());
pPollArr[idx++].events |= POLLIN;
}
SocketList::iterator begR = readList.begin();
SocketList::iterator endR = readList.end();
for (SocketList::iterator it = writeList.begin(); it != writeList.end(); ++it)
{
SocketList::iterator pos = std::find(begR, endR, *it);
if (pos != endR)
{
pPollArr[pos-begR].events |= POLLOUT;
--nfd;
}
else
{
pPollArr[idx].fd = int(it->sockfd());
pPollArr[idx++].events |= POLLOUT;
}
}
SocketList::iterator begW = writeList.begin();
SocketList::iterator endW = writeList.end();
for (SocketList::iterator it = exceptList.begin(); it != exceptList.end(); ++it)
{
SocketList::iterator pos = std::find(begR, endR, *it);
if (pos != endR) --nfd;
else
{
SocketList::iterator pos = std::find(begW, endW, *it);
if (pos != endW) --nfd;
else pPollArr[idx++].fd = int(it->sockfd());
}
}
Poco::Timespan remainingTime(timeout);
int rc;
do
{
Poco::Timestamp start;
rc = ::poll(pPollArr, nfd, remainingTime.totalMilliseconds());
if (rc < 0 && SocketImpl::lastError() == POCO_EINTR)
{
Poco::Timestamp end;
Poco::Timespan waited = end - start;
if (waited < remainingTime) remainingTime -= waited;
else remainingTime = 0;
}
}
while (rc < 0 && SocketImpl::lastError() == POCO_EINTR);
if (rc < 0) SocketImpl::error();
SocketList readyReadList;
SocketList readyWriteList;
SocketList readyExceptList;
SocketList::iterator begE = exceptList.begin();
SocketList::iterator endE = exceptList.end();
for (int idx = 0; idx < nfd; ++idx)
{
SocketList::iterator slIt = std::find_if(begR, endR, Socket::FDCompare(pPollArr[idx].fd));
if (POLLIN & pPollArr[idx].revents && slIt != endR) readyReadList.push_back(*slIt);
slIt = std::find_if(begW, endW, Socket::FDCompare(pPollArr[idx].fd));
if (POLLOUT & pPollArr[idx].revents && slIt != endW) readyWriteList.push_back(*slIt);
slIt = std::find_if(begE, endE, Socket::FDCompare(pPollArr[idx].fd));
if (POLLERR & pPollArr[idx].revents && slIt != endE) readyExceptList.push_back(*slIt);
}
std::swap(readList, readyReadList);
std::swap(writeList, readyWriteList);
std::swap(exceptList, readyExceptList);
return readList.size() + writeList.size() + exceptList.size();
#else
fd_set fdRead;
fd_set fdWrite;
fd_set fdExcept;
int nfd = 0;
FD_ZERO(&fdRead);
for (SocketList::const_iterator it = readList.begin(); it != readList.end(); ++it)
{
poco_socket_t fd = it->sockfd();
if (fd != POCO_INVALID_SOCKET)
{
if (int(fd) > nfd)
nfd = int(fd);
FD_SET(fd, &fdRead);
}
}
FD_ZERO(&fdWrite);
for (SocketList::const_iterator it = writeList.begin(); it != writeList.end(); ++it)
{
poco_socket_t fd = it->sockfd();
if (fd != POCO_INVALID_SOCKET)
{
if (int(fd) > nfd)
nfd = int(fd);
FD_SET(fd, &fdWrite);
}
}
FD_ZERO(&fdExcept);
for (SocketList::const_iterator it = exceptList.begin(); it != exceptList.end(); ++it)
{
poco_socket_t fd = it->sockfd();
if (fd != POCO_INVALID_SOCKET)
{
if (int(fd) > nfd)
nfd = int(fd);
FD_SET(fd, &fdExcept);
}
}
if (nfd == 0) return 0;
Poco::Timespan remainingTime(timeout);
int rc;
do
{
struct timeval tv;
tv.tv_sec = (long) remainingTime.totalSeconds();
tv.tv_usec = (long) remainingTime.useconds();
Poco::Timestamp start;
rc = ::select(nfd + 1, &fdRead, &fdWrite, &fdExcept, &tv);
if (rc < 0 && SocketImpl::lastError() == POCO_EINTR)
{
Poco::Timestamp end;
Poco::Timespan waited = end - start;
if (waited < remainingTime)
remainingTime -= waited;
else
remainingTime = 0;
}
}
while (rc < 0 && SocketImpl::lastError() == POCO_EINTR);
if (rc < 0) SocketImpl::error();
SocketList readyReadList;
for (SocketList::const_iterator it = readList.begin(); it != readList.end(); ++it)
{
poco_socket_t fd = it->sockfd();
if (fd != POCO_INVALID_SOCKET)
{
if (FD_ISSET(fd, &fdRead))
readyReadList.push_back(*it);
}
}
std::swap(readList, readyReadList);
SocketList readyWriteList;
for (SocketList::const_iterator it = writeList.begin(); it != writeList.end(); ++it)
{
poco_socket_t fd = it->sockfd();
if (fd != POCO_INVALID_SOCKET)
{
if (FD_ISSET(fd, &fdWrite))
readyWriteList.push_back(*it);
}
}
std::swap(writeList, readyWriteList);
SocketList readyExceptList;
for (SocketList::const_iterator it = exceptList.begin(); it != exceptList.end(); ++it)
{
poco_socket_t fd = it->sockfd();
if (fd != POCO_INVALID_SOCKET)
{
if (FD_ISSET(fd, &fdExcept))
readyExceptList.push_back(*it);
}
}
std::swap(exceptList, readyExceptList);
return rc;
#endif // POCO_HAVE_FD_EPOLL
}
SocketBufVec Socket::makeBufVec(std::size_t size, std::size_t bufLen)
{
SocketBufVec buf(size);
SocketBufVec::iterator it = buf.begin();
SocketBufVec::iterator end = buf.end();
for (; it != end; ++it)
{
// TODO: use memory pool
*it = makeBuffer(malloc(bufLen), bufLen);
}
return buf;
}
void Socket::destroyBufVec(SocketBufVec& buf)
{
SocketBufVec::iterator it = buf.begin();
SocketBufVec::iterator end = buf.end();
for (; it != end; ++it)
{
#if defined(POCO_OS_FAMILY_WINDOWS)
free(it->buf);
#elif defined(POCO_OS_FAMILY_UNIX)
free(it->iov_base);
#endif
}
SocketBufVec().swap(buf);
}
SocketBuf Socket::makeBuffer(void* buffer, std::size_t length)
{
SocketBuf ret;
#if defined(POCO_OS_FAMILY_WINDOWS)
ret.buf = reinterpret_cast<char*>(buffer);
ret.len = static_cast<ULONG>(length);
#elif defined(POCO_OS_FAMILY_UNIX)
ret.iov_base = buffer;
ret.iov_len = length;
#else
throw NotImplementedException("Socket::makeBuffer(void*, size_t)");
#endif
return ret;
}
SocketBufVec Socket::makeBufVec(const std::vector<char*>& vec)
{
SocketBufVec buf(vec.size());
SocketBufVec::iterator it = buf.begin();
SocketBufVec::iterator end = buf.end();
std::vector<char*>::const_iterator vIt = vec.begin();
for (; it != end; ++it, ++vIt)
{
*it = makeBuffer(*vIt, strlen(*vIt));
}
return buf;
}
SocketBufVec Socket::makeBufVec(const std::vector<std::string>& vec)
{
SocketBufVec buf(vec.size());
SocketBufVec::iterator it = buf.begin();
SocketBufVec::iterator end = buf.end();
std::vector<std::string>::const_iterator vIt = vec.begin();
for (; it != end; ++it, ++vIt)
{
char* c = const_cast<char*>(vIt->data());
*it = makeBuffer(reinterpret_cast<void*>(c), vIt->size());
}
return buf;
}
} } // namespace Poco::Net
+435
View File
@@ -0,0 +1,435 @@
//
// SocketAddress.cpp
//
// Library: Net
// Package: NetCore
// Module: SocketAddress
//
// Copyright (c) 2005-2011, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/SocketAddress.h"
#include "Poco/Net/IPAddress.h"
#include "Poco/Net/NetException.h"
#include "Poco/Net/DNS.h"
#include "Poco/RefCountedObject.h"
#include "Poco/NumberParser.h"
#include "Poco/BinaryReader.h"
#include "Poco/BinaryWriter.h"
#include <algorithm>
#include <cstring>
using Poco::RefCountedObject;
using Poco::NumberParser;
using Poco::UInt16;
using Poco::InvalidArgumentException;
using Poco::Net::Impl::SocketAddressImpl;
using Poco::Net::Impl::IPv4SocketAddressImpl;
#ifdef POCO_HAVE_IPv6
using Poco::Net::Impl::IPv6SocketAddressImpl;
#endif
#ifdef POCO_OS_FAMILY_UNIX
using Poco::Net::Impl::LocalSocketAddressImpl;
#endif
namespace Poco {
namespace Net {
struct AFLT
{
bool operator () (const IPAddress& a1, const IPAddress& a2)
{
return a1.af() < a2.af();
}
};
//
// SocketAddress
//
#if !defined(_MSC_VER) || defined(__STDC__)
// Go home MSVC, you're drunk...
// See http://stackoverflow.com/questions/5899857/multiple-definition-error-for-static-const-class-members
const SocketAddress::Family SocketAddress::IPv4;
#if defined(POCO_HAVE_IPv6)
const SocketAddress::Family SocketAddress::IPv6;
#endif
#if defined(POCO_OS_FAMILY_UNIX)
const SocketAddress::Family SocketAddress::UNIX_LOCAL;
#endif
#endif
SocketAddress::SocketAddress()
{
newIPv4();
}
SocketAddress::SocketAddress(Family fam)
{
init(IPAddress(fam), 0);
}
SocketAddress::SocketAddress(const IPAddress& hostAddress, Poco::UInt16 portNumber)
{
init(hostAddress, portNumber);
}
SocketAddress::SocketAddress(Poco::UInt16 portNumber)
{
init(IPAddress(), portNumber);
}
SocketAddress::SocketAddress(Family fam, Poco::UInt16 portNumber)
{
init(IPAddress(fam), portNumber);
}
SocketAddress::SocketAddress(const std::string& hostAddress, Poco::UInt16 portNumber)
{
init(hostAddress, portNumber);
}
SocketAddress::SocketAddress(Family fam, const std::string& hostAddress, Poco::UInt16 portNumber)
{
init(fam, hostAddress, portNumber);
}
SocketAddress::SocketAddress(const std::string& hostAddress, const std::string& portNumber)
{
init(hostAddress, resolveService(portNumber));
}
SocketAddress::SocketAddress(Family fam, const std::string& hostAddress, const std::string& portNumber)
{
init(fam, hostAddress, resolveService(portNumber));
}
SocketAddress::SocketAddress(Family fam, const std::string& addr)
{
init(fam, addr);
}
SocketAddress::SocketAddress(const std::string& hostAndPort)
{
init(hostAndPort);
}
SocketAddress::SocketAddress(const SocketAddress& socketAddress)
{
if (socketAddress.family() == IPv4)
newIPv4(reinterpret_cast<const sockaddr_in*>(socketAddress.addr()));
#if defined(POCO_HAVE_IPv6)
else if (socketAddress.family() == IPv6)
newIPv6(reinterpret_cast<const sockaddr_in6*>(socketAddress.addr()));
#endif
#if defined(POCO_OS_FAMILY_UNIX)
else if (socketAddress.family() == UNIX_LOCAL)
newLocal(reinterpret_cast<const sockaddr_un*>(socketAddress.addr()));
#endif
}
SocketAddress::SocketAddress(const struct sockaddr* sockAddr, poco_socklen_t length)
{
if (length == sizeof(struct sockaddr_in) && sockAddr->sa_family == AF_INET)
newIPv4(reinterpret_cast<const struct sockaddr_in*>(sockAddr));
#if defined(POCO_HAVE_IPv6)
else if (length == sizeof(struct sockaddr_in6) && sockAddr->sa_family == AF_INET6)
newIPv6(reinterpret_cast<const struct sockaddr_in6*>(sockAddr));
#endif
#if defined(POCO_OS_FAMILY_UNIX)
else if (length > 0 && length <= sizeof(struct sockaddr_un) && sockAddr->sa_family == AF_UNIX)
newLocal(reinterpret_cast<const sockaddr_un*>(sockAddr));
#endif
else throw Poco::InvalidArgumentException("Invalid address length or family passed to SocketAddress()");
}
SocketAddress::~SocketAddress()
{
}
bool SocketAddress::operator < (const SocketAddress& socketAddress) const
{
if (family() < socketAddress.family()) return true;
if (family() > socketAddress.family()) return false;
#if defined(POCO_OS_FAMILY_UNIX)
if (family() == UNIX_LOCAL) return toString() < socketAddress.toString();
#endif
if (host() < socketAddress.host()) return true;
if (host() > socketAddress.host()) return false;
return (port() < socketAddress.port());
}
SocketAddress& SocketAddress::operator = (const SocketAddress& socketAddress)
{
if (&socketAddress != this)
{
if (socketAddress.family() == IPv4)
newIPv4(reinterpret_cast<const sockaddr_in*>(socketAddress.addr()));
#if defined(POCO_HAVE_IPv6)
else if (socketAddress.family() == IPv6)
newIPv6(reinterpret_cast<const sockaddr_in6*>(socketAddress.addr()));
#endif
#if defined(POCO_OS_FAMILY_UNIX)
else if (socketAddress.family() == UNIX_LOCAL)
newLocal(reinterpret_cast<const sockaddr_un*>(socketAddress.addr()));
#endif
}
return *this;
}
IPAddress SocketAddress::host() const
{
return pImpl()->host();
}
Poco::UInt16 SocketAddress::port() const
{
return ntohs(pImpl()->port());
}
poco_socklen_t SocketAddress::length() const
{
return pImpl()->length();
}
const struct sockaddr* SocketAddress::addr() const
{
return pImpl()->addr();
}
int SocketAddress::af() const
{
return pImpl()->af();
}
SocketAddress::Family SocketAddress::family() const
{
return static_cast<Family>(pImpl()->family());
}
std::string SocketAddress::toString() const
{
return pImpl()->toString();
}
void SocketAddress::init(const IPAddress& hostAddress, Poco::UInt16 portNumber)
{
if (hostAddress.family() == IPAddress::IPv4)
newIPv4(hostAddress, portNumber);
#if defined(POCO_HAVE_IPv6)
else if (hostAddress.family() == IPAddress::IPv6)
newIPv6(hostAddress, portNumber);
#endif
else throw Poco::NotImplementedException("unsupported IP address family");
}
void SocketAddress::init(const std::string& hostAddress, Poco::UInt16 portNumber)
{
IPAddress ip;
if (IPAddress::tryParse(hostAddress, ip))
{
init(ip, portNumber);
}
else
{
HostEntry he = DNS::hostByName(hostAddress);
HostEntry::AddressList addresses = he.addresses();
if (addresses.size() > 0)
{
#if defined(POCO_HAVE_IPv6) && defined(POCO_SOCKETADDRESS_PREFER_IPv4)
// if we get both IPv4 and IPv6 addresses, prefer IPv4
std::stable_sort(addresses.begin(), addresses.end(), AFLT());
#endif
init(addresses[0], portNumber);
}
else throw HostNotFoundException("No address found for host", hostAddress);
}
}
void SocketAddress::init(Family fam, const std::string& hostAddress, Poco::UInt16 portNumber)
{
IPAddress ip;
if (IPAddress::tryParse(hostAddress, ip))
{
if (ip.family() != fam) throw AddressFamilyMismatchException(hostAddress);
init(ip, portNumber);
}
else
{
HostEntry he = DNS::hostByName(hostAddress);
HostEntry::AddressList addresses = he.addresses();
if (addresses.size() > 0)
{
for (const auto& addr: addresses)
{
if (addr.family() == fam)
{
init(addr, portNumber);
return;
}
}
throw AddressFamilyMismatchException(hostAddress);
}
else throw HostNotFoundException("No address found for host", hostAddress);
}
}
void SocketAddress::init(Family fam, const std::string& address)
{
#if defined(POCO_OS_FAMILY_UNIX)
if (fam == UNIX_LOCAL)
{
newLocal(address);
}
else
#endif
{
std::string host;
std::string port;
std::string::const_iterator it = address.begin();
std::string::const_iterator end = address.end();
if (*it == '[')
{
++it;
while (it != end && *it != ']') host += *it++;
if (it == end) throw InvalidArgumentException("Malformed IPv6 address");
++it;
}
else
{
while (it != end && *it != ':') host += *it++;
}
if (it != end && *it == ':')
{
++it;
while (it != end) port += *it++;
}
else throw InvalidArgumentException("Missing port number");
init(fam, host, resolveService(port));
}
}
void SocketAddress::init(const std::string& hostAndPort)
{
poco_assert (!hostAndPort.empty());
std::string host;
std::string port;
std::string::const_iterator it = hostAndPort.begin();
std::string::const_iterator end = hostAndPort.end();
#if defined(POCO_OS_FAMILY_UNIX)
if (*it == '/')
{
newLocal(hostAndPort);
return;
}
#endif
if (*it == '[')
{
++it;
while (it != end && *it != ']') host += *it++;
if (it == end) throw InvalidArgumentException("Malformed IPv6 address");
++it;
}
else
{
while (it != end && *it != ':') host += *it++;
}
if (it != end && *it == ':')
{
++it;
while (it != end) port += *it++;
}
else throw InvalidArgumentException("Missing port number");
init(host, resolveService(port));
}
Poco::UInt16 SocketAddress::resolveService(const std::string& service)
{
unsigned port;
if (NumberParser::tryParseUnsigned(service, port) && port <= 0xFFFF)
{
return (UInt16) port;
}
else
{
#if defined(POCO_VXWORKS)
throw ServiceNotFoundException(service);
#else
struct servent* se = getservbyname(service.c_str(), NULL);
if (se)
return ntohs(se->s_port);
else
throw ServiceNotFoundException(service);
#endif
}
}
} } // namespace Poco::Net
Poco::BinaryWriter& operator << (Poco::BinaryWriter& writer, const Poco::Net::SocketAddress& value)
{
writer << value.host();
writer << value.port();
return writer;
}
Poco::BinaryReader& operator >> (Poco::BinaryReader& reader, Poco::Net::SocketAddress& value)
{
Poco::Net::IPAddress host;
reader >> host;
Poco::UInt16 port;
reader >> port;
value = Poco::Net::SocketAddress(host, port);
return reader;
}
std::ostream& operator << (std::ostream& ostr, const Poco::Net::SocketAddress& address)
{
ostr << address.toString();
return ostr;
}
+184
View File
@@ -0,0 +1,184 @@
//
// SocketAddressImpl.cpp
//
// Library: Net
// Package: NetCore
// Module: SocketAddressImpl
//
// Copyright (c) 2005-2011, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/SocketAddressImpl.h"
#include "Poco/Net/SocketDefs.h"
#include "Poco/NumberFormatter.h"
#include <cstring>
namespace Poco {
namespace Net {
namespace Impl {
//
// SocketAddressImpl
//
SocketAddressImpl::SocketAddressImpl()
{
}
SocketAddressImpl::~SocketAddressImpl()
{
}
//
// IPv4SocketAddressImpl
//
IPv4SocketAddressImpl::IPv4SocketAddressImpl()
{
std::memset(&_addr, 0, sizeof(_addr));
_addr.sin_family = AF_INET;
poco_set_sin_len(&_addr);
}
IPv4SocketAddressImpl::IPv4SocketAddressImpl(const struct sockaddr_in* addr)
{
std::memcpy(&_addr, addr, sizeof(_addr));
}
IPv4SocketAddressImpl::IPv4SocketAddressImpl(const void* addr, UInt16 port)
{
std::memset(&_addr, 0, sizeof(_addr));
_addr.sin_family = AF_INET;
poco_set_sin_len(&_addr);
std::memcpy(&_addr.sin_addr, addr, sizeof(_addr.sin_addr));
_addr.sin_port = port;
}
std::string IPv4SocketAddressImpl::toString() const
{
std::string result;
result.append(host().toString());
result.append(":");
NumberFormatter::append(result, ntohs(port()));
return result;
}
#if defined(POCO_HAVE_IPv6)
//
// IPv6SocketAddressImpl
//
IPv6SocketAddressImpl::IPv6SocketAddressImpl(const struct sockaddr_in6* addr)
{
std::memcpy(&_addr, addr, sizeof(_addr));
}
IPv6SocketAddressImpl::IPv6SocketAddressImpl(const void* addr, UInt16 port)
{
std::memset(&_addr, 0, sizeof(_addr));
_addr.sin6_family = AF_INET6;
poco_set_sin6_len(&_addr);
std::memcpy(&_addr.sin6_addr, addr, sizeof(_addr.sin6_addr));
_addr.sin6_port = port;
}
IPv6SocketAddressImpl::IPv6SocketAddressImpl(const void* addr, UInt16 port, UInt32 scope)
{
std::memset(&_addr, 0, sizeof(_addr));
_addr.sin6_family = AF_INET6;
poco_set_sin6_len(&_addr);
std::memcpy(&_addr.sin6_addr, addr, sizeof(_addr.sin6_addr));
_addr.sin6_port = port;
_addr.sin6_scope_id = scope;
}
std::string IPv6SocketAddressImpl::toString() const
{
std::string result;
result.append("[");
result.append(host().toString());
result.append("]");
result.append(":");
NumberFormatter::append(result, ntohs(port()));
return result;
}
#endif // POCO_HAVE_IPv6
#if defined(POCO_OS_FAMILY_UNIX)
//
// LocalSocketAddressImpl
//
LocalSocketAddressImpl::LocalSocketAddressImpl(const struct sockaddr_un* addr)
{
_pAddr = new sockaddr_un;
std::memcpy(_pAddr, addr, sizeof(struct sockaddr_un));
}
LocalSocketAddressImpl::LocalSocketAddressImpl(const char* path)
{
poco_assert (std::strlen(path) < sizeof(_pAddr->sun_path));
_pAddr = new sockaddr_un;
poco_set_sun_len(_pAddr, std::strlen(path) + sizeof(struct sockaddr_un) - sizeof(_pAddr->sun_path) + 1);
_pAddr->sun_family = AF_UNIX;
std::strcpy(_pAddr->sun_path, path);
}
LocalSocketAddressImpl::LocalSocketAddressImpl(const char* path, std::size_t length)
{
poco_assert (length < sizeof(_pAddr->sun_path));
_pAddr = new sockaddr_un;
poco_set_sun_len(_pAddr, length + sizeof(struct sockaddr_un) - sizeof(_pAddr->sun_path) + 1);
_pAddr->sun_family = AF_UNIX;
std::memcpy(_pAddr->sun_path, path, length);
_pAddr->sun_path[length] = 0;
}
LocalSocketAddressImpl::~LocalSocketAddressImpl()
{
delete _pAddr;
}
std::string LocalSocketAddressImpl::toString() const
{
std::string result(path());
return result;
}
#endif // POCO_OS_FAMILY_UNIX
} } } // namespace Poco::Net::Impl
+1304
View File
File diff suppressed because it is too large Load Diff
+105
View File
@@ -0,0 +1,105 @@
//
// SocketNotification.cpp
//
// Library: Net
// Package: Reactor
// Module: SocketNotification
//
// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/SocketNotification.h"
namespace Poco {
namespace Net {
SocketNotification::SocketNotification(SocketReactor* pReactor):
_pReactor(pReactor)
{
}
SocketNotification::~SocketNotification()
{
}
void SocketNotification::setSocket(const Socket& socket)
{
_socket = socket;
}
ReadableNotification::ReadableNotification(SocketReactor* pReactor):
SocketNotification(pReactor)
{
}
ReadableNotification::~ReadableNotification()
{
}
WritableNotification::WritableNotification(SocketReactor* pReactor):
SocketNotification(pReactor)
{
}
WritableNotification::~WritableNotification()
{
}
ErrorNotification::ErrorNotification(SocketReactor* pReactor):
SocketNotification(pReactor)
{
}
ErrorNotification::~ErrorNotification()
{
}
TimeoutNotification::TimeoutNotification(SocketReactor* pReactor):
SocketNotification(pReactor)
{
}
TimeoutNotification::~TimeoutNotification()
{
}
IdleNotification::IdleNotification(SocketReactor* pReactor):
SocketNotification(pReactor)
{
}
IdleNotification::~IdleNotification()
{
}
ShutdownNotification::ShutdownNotification(SocketReactor* pReactor):
SocketNotification(pReactor)
{
}
ShutdownNotification::~ShutdownNotification()
{
}
} } // namespace Poco::Net
+91
View File
@@ -0,0 +1,91 @@
//
// SocketNotifier.cpp
//
// Library: Net
// Package: Reactor
// Module: SocketNotifier
//
// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/SocketNotifier.h"
#include "Poco/Net/SocketReactor.h"
#include "Poco/Net/SocketNotification.h"
namespace Poco {
namespace Net {
SocketNotifier::SocketNotifier(const Socket& socket):
_socket(socket)
{
}
SocketNotifier::~SocketNotifier()
{
}
void SocketNotifier::addObserver(SocketReactor* pReactor, const Poco::AbstractObserver& observer)
{
_nc.addObserver(observer);
ScopedLock l(_mutex);
if (observer.accepts(pReactor->_pReadableNotification))
_events.insert(pReactor->_pReadableNotification.get());
else if (observer.accepts(pReactor->_pWritableNotification))
_events.insert(pReactor->_pWritableNotification.get());
else if (observer.accepts(pReactor->_pErrorNotification))
_events.insert(pReactor->_pErrorNotification.get());
else if (observer.accepts(pReactor->_pTimeoutNotification))
_events.insert(pReactor->_pTimeoutNotification.get());
}
void SocketNotifier::removeObserver(SocketReactor* pReactor, const Poco::AbstractObserver& observer)
{
_nc.removeObserver(observer);
ScopedLock l(_mutex);
EventSet::iterator it = _events.end();
if (observer.accepts(pReactor->_pReadableNotification))
it = _events.find(pReactor->_pReadableNotification.get());
else if (observer.accepts(pReactor->_pWritableNotification))
it = _events.find(pReactor->_pWritableNotification.get());
else if (observer.accepts(pReactor->_pErrorNotification))
it = _events.find(pReactor->_pErrorNotification.get());
else if (observer.accepts(pReactor->_pTimeoutNotification))
it = _events.find(pReactor->_pTimeoutNotification.get());
if (it != _events.end())
_events.erase(it);
}
namespace
{
static Socket nullSocket;
}
void SocketNotifier::dispatch(SocketNotification* pNotification)
{
pNotification->setSocket(_socket);
pNotification->duplicate();
try
{
_nc.postNotification(pNotification);
}
catch (...)
{
pNotification->setSocket(nullSocket);
throw;
}
pNotification->setSocket(nullSocket);
}
} } // namespace Poco::Net
+284
View File
@@ -0,0 +1,284 @@
//
// SocketReactor.cpp
//
// Library: Net
// Package: Reactor
// Module: SocketReactor
//
// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/SocketReactor.h"
#include "Poco/Net/SocketNotification.h"
#include "Poco/Net/SocketNotifier.h"
#include "Poco/ErrorHandler.h"
#include "Poco/Thread.h"
#include "Poco/Exception.h"
using Poco::Exception;
using Poco::ErrorHandler;
namespace Poco {
namespace Net {
SocketReactor::SocketReactor():
_stop(false),
_timeout(DEFAULT_TIMEOUT),
_pReadableNotification(new ReadableNotification(this)),
_pWritableNotification(new WritableNotification(this)),
_pErrorNotification(new ErrorNotification(this)),
_pTimeoutNotification(new TimeoutNotification(this)),
_pIdleNotification(new IdleNotification(this)),
_pShutdownNotification(new ShutdownNotification(this)),
_pThread(0)
{
}
SocketReactor::SocketReactor(const Poco::Timespan& timeout):
_stop(false),
_timeout(timeout),
_pReadableNotification(new ReadableNotification(this)),
_pWritableNotification(new WritableNotification(this)),
_pErrorNotification(new ErrorNotification(this)),
_pTimeoutNotification(new TimeoutNotification(this)),
_pIdleNotification(new IdleNotification(this)),
_pShutdownNotification(new ShutdownNotification(this)),
_pThread(0)
{
}
SocketReactor::~SocketReactor()
{
}
void SocketReactor::run()
{
_pThread = Thread::current();
while (!_stop)
{
try
{
if (!hasSocketHandlers())
{
onIdle();
Thread::trySleep(static_cast<long>(_timeout.totalMilliseconds()));
}
else
{
bool readable = false;
PollSet::SocketModeMap sm = _pollSet.poll(_timeout);
if (sm.size() > 0)
{
onBusy();
PollSet::SocketModeMap::iterator it = sm.begin();
PollSet::SocketModeMap::iterator end = sm.end();
for (; it != end; ++it)
{
if (it->second & PollSet::POLL_READ)
{
dispatch(it->first, _pReadableNotification);
readable = true;
}
if (it->second & PollSet::POLL_WRITE) dispatch(it->first, _pWritableNotification);
if (it->second & PollSet::POLL_ERROR) dispatch(it->first, _pErrorNotification);
}
}
if (!readable) onTimeout();
}
}
catch (Exception& exc)
{
ErrorHandler::handle(exc);
}
catch (std::exception& exc)
{
ErrorHandler::handle(exc);
}
catch (...)
{
ErrorHandler::handle();
}
}
onShutdown();
}
bool SocketReactor::hasSocketHandlers()
{
if (!_pollSet.empty())
{
ScopedLock lock(_mutex);
for (auto& p: _handlers)
{
if (p.second->accepts(_pReadableNotification) ||
p.second->accepts(_pWritableNotification) ||
p.second->accepts(_pErrorNotification)) return true;
}
}
return false;
}
void SocketReactor::stop()
{
_stop = true;
}
void SocketReactor::wakeUp()
{
if (_pThread) _pThread->wakeUp();
}
void SocketReactor::setTimeout(const Poco::Timespan& timeout)
{
_timeout = timeout;
}
const Poco::Timespan& SocketReactor::getTimeout() const
{
return _timeout;
}
void SocketReactor::addEventHandler(const Socket& socket, const Poco::AbstractObserver& observer)
{
NotifierPtr pNotifier = getNotifier(socket, true);
if (!pNotifier->hasObserver(observer)) pNotifier->addObserver(this, observer);
int mode = 0;
if (pNotifier->accepts(_pReadableNotification)) mode |= PollSet::POLL_READ;
if (pNotifier->accepts(_pWritableNotification)) mode |= PollSet::POLL_WRITE;
if (pNotifier->accepts(_pErrorNotification)) mode |= PollSet::POLL_ERROR;
if (mode) _pollSet.add(socket, mode);
}
bool SocketReactor::hasEventHandler(const Socket& socket, const Poco::AbstractObserver& observer)
{
NotifierPtr pNotifier = getNotifier(socket);
if (!pNotifier) return false;
if (pNotifier->hasObserver(observer)) return true;
return false;
}
SocketReactor::NotifierPtr SocketReactor::getNotifier(const Socket& socket, bool makeNew)
{
ScopedLock lock(_mutex);
EventHandlerMap::iterator it = _handlers.find(socket);
if (it != _handlers.end()) return it->second;
else if (makeNew) return (_handlers[socket] = new SocketNotifier(socket));
return 0;
}
void SocketReactor::removeEventHandler(const Socket& socket, const Poco::AbstractObserver& observer)
{
NotifierPtr pNotifier = getNotifier(socket);
if (pNotifier && pNotifier->hasObserver(observer))
{
if(pNotifier->countObservers() == 1)
{
{
ScopedLock lock(_mutex);
_handlers.erase(socket);
}
_pollSet.remove(socket);
}
pNotifier->removeObserver(this, observer);
}
}
bool SocketReactor::has(const Socket& socket) const
{
return _pollSet.has(socket);
}
void SocketReactor::onTimeout()
{
dispatch(_pTimeoutNotification);
}
void SocketReactor::onIdle()
{
dispatch(_pIdleNotification);
}
void SocketReactor::onShutdown()
{
dispatch(_pShutdownNotification);
}
void SocketReactor::onBusy()
{
}
void SocketReactor::dispatch(const Socket& socket, SocketNotification* pNotification)
{
NotifierPtr pNotifier = getNotifier(socket);
if (!pNotifier) return;
dispatch(pNotifier, pNotification);
}
void SocketReactor::dispatch(SocketNotification* pNotification)
{
std::vector<NotifierPtr> delegates;
{
ScopedLock lock(_mutex);
delegates.reserve(_handlers.size());
for (EventHandlerMap::iterator it = _handlers.begin(); it != _handlers.end(); ++it)
delegates.push_back(it->second);
}
for (std::vector<NotifierPtr>::iterator it = delegates.begin(); it != delegates.end(); ++it)
{
dispatch(*it, pNotification);
}
}
void SocketReactor::dispatch(NotifierPtr& pNotifier, SocketNotification* pNotification)
{
try
{
pNotifier->dispatch(pNotification);
}
catch (Exception& exc)
{
ErrorHandler::handle(exc);
}
catch (std::exception& exc)
{
ErrorHandler::handle(exc);
}
catch (...)
{
ErrorHandler::handle();
}
}
} } // namespace Poco::Net
+156
View File
@@ -0,0 +1,156 @@
//
// SocketStream.cpp
//
// Library: Net
// Package: Sockets
// Module: SocketStream
//
// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/SocketStream.h"
#include "Poco/Net/StreamSocketImpl.h"
#include "Poco/Exception.h"
using Poco::BufferedBidirectionalStreamBuf;
using Poco::InvalidArgumentException;
namespace Poco {
namespace Net {
//
// SocketStreamBuf
//
SocketStreamBuf::SocketStreamBuf(const Socket& socket):
BufferedBidirectionalStreamBuf(STREAM_BUFFER_SIZE, std::ios::in | std::ios::out),
_pImpl(dynamic_cast<StreamSocketImpl*>(socket.impl()))
{
if (_pImpl)
_pImpl->duplicate();
else
throw InvalidArgumentException("Invalid or null SocketImpl passed to SocketStreamBuf");
}
SocketStreamBuf::~SocketStreamBuf()
{
_pImpl->release();
}
int SocketStreamBuf::readFromDevice(char* buffer, std::streamsize length)
{
return _pImpl->receiveBytes(buffer, (int) length);
}
int SocketStreamBuf::writeToDevice(const char* buffer, std::streamsize length)
{
return _pImpl->sendBytes(buffer, (int) length);
}
//
// SocketIOS
//
SocketIOS::SocketIOS(const Socket& socket):
_buf(socket)
{
poco_ios_init(&_buf);
}
SocketIOS::~SocketIOS()
{
try
{
_buf.sync();
}
catch (...)
{
}
}
SocketStreamBuf* SocketIOS::rdbuf()
{
return &_buf;
}
void SocketIOS::close()
{
_buf.sync();
_buf.socketImpl()->close();
}
StreamSocket SocketIOS::socket() const
{
return StreamSocket(_buf.socketImpl());
}
//
// SocketOutputStream
//
SocketOutputStream::SocketOutputStream(const Socket& socket):
SocketIOS(socket),
std::ostream(&_buf)
{
}
SocketOutputStream::~SocketOutputStream()
{
}
//
// SocketInputStream
//
SocketInputStream::SocketInputStream(const Socket& socket):
SocketIOS(socket),
std::istream(&_buf)
{
}
SocketInputStream::~SocketInputStream()
{
}
//
// SocketStream
//
SocketStream::SocketStream(const Socket& socket):
SocketIOS(socket),
std::iostream(&_buf)
{
}
SocketStream::~SocketStream()
{
}
} } // namespace Poco::Net
+168
View File
@@ -0,0 +1,168 @@
//
// StreamSocket.cpp
//
// Library: Net
// Package: Sockets
// Module: StreamSocket
//
// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/StreamSocket.h"
#include "Poco/Net/StreamSocketImpl.h"
#include "Poco/FIFOBuffer.h"
#include "Poco/Mutex.h"
#include "Poco/Exception.h"
using Poco::InvalidArgumentException;
using Poco::Mutex;
using Poco::ScopedLock;
namespace Poco {
namespace Net {
StreamSocket::StreamSocket(): Socket(new StreamSocketImpl)
{
}
StreamSocket::StreamSocket(const SocketAddress& address): Socket(new StreamSocketImpl(address.family()))
{
connect(address);
}
StreamSocket::StreamSocket(SocketAddress::Family family): Socket(new StreamSocketImpl(family))
{
}
StreamSocket::StreamSocket(const Socket& socket): Socket(socket)
{
if (!dynamic_cast<StreamSocketImpl*>(impl()))
throw InvalidArgumentException("Cannot assign incompatible socket");
}
StreamSocket::StreamSocket(SocketImpl* pImpl): Socket(pImpl)
{
if (!dynamic_cast<StreamSocketImpl*>(impl()))
throw InvalidArgumentException("Cannot assign incompatible socket");
}
StreamSocket::~StreamSocket()
{
}
StreamSocket& StreamSocket::operator = (const Socket& socket)
{
if (dynamic_cast<StreamSocketImpl*>(socket.impl()))
Socket::operator = (socket);
else
throw InvalidArgumentException("Cannot assign incompatible socket");
return *this;
}
void StreamSocket::connect(const SocketAddress& address)
{
impl()->connect(address);
}
void StreamSocket::connect(const SocketAddress& address, const Poco::Timespan& timeout)
{
impl()->connect(address, timeout);
}
void StreamSocket::connectNB(const SocketAddress& address)
{
impl()->connectNB(address);
}
void StreamSocket::shutdownReceive()
{
impl()->shutdownReceive();
}
void StreamSocket::shutdownSend()
{
impl()->shutdownSend();
}
void StreamSocket::shutdown()
{
impl()->shutdown();
}
int StreamSocket::sendBytes(const void* buffer, int length, int flags)
{
return impl()->sendBytes(buffer, length, flags);
}
int StreamSocket::sendBytes(const SocketBufVec& buffers, int flags)
{
return impl()->sendBytes(buffers, flags);
}
int StreamSocket::sendBytes(FIFOBuffer& fifoBuf)
{
ScopedLock<Mutex> l(fifoBuf.mutex());
int ret = impl()->sendBytes(fifoBuf.begin(), (int) fifoBuf.used());
if (ret > 0) fifoBuf.drain(ret);
return ret;
}
int StreamSocket::receiveBytes(void* buffer, int length, int flags)
{
return impl()->receiveBytes(buffer, length, flags);
}
int StreamSocket::receiveBytes(SocketBufVec& buffers, int flags)
{
return impl()->receiveBytes(buffers, flags);
}
int StreamSocket::receiveBytes(Poco::Buffer<char>& buffer, int flags, const Poco::Timespan& timeout)
{
return impl()->receiveBytes(buffer, flags, timeout);
}
int StreamSocket::receiveBytes(FIFOBuffer& fifoBuf)
{
ScopedLock<Mutex> l(fifoBuf.mutex());
int ret = impl()->receiveBytes(fifoBuf.next(), (int)fifoBuf.available());
if (ret > 0) fifoBuf.advance(ret);
return ret;
}
void StreamSocket::sendUrgent(unsigned char data)
{
impl()->sendUrgent(data);
}
} } // namespace Poco::Net
+77
View File
@@ -0,0 +1,77 @@
//
// StreamSocketImpl.cpp
//
// Library: Net
// Package: Sockets
// Module: StreamSocketImpl
//
// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/StreamSocketImpl.h"
#include "Poco/Exception.h"
#include "Poco/Thread.h"
namespace Poco {
namespace Net {
StreamSocketImpl::StreamSocketImpl()
{
}
StreamSocketImpl::StreamSocketImpl(SocketAddress::Family family)
{
if (family == SocketAddress::IPv4)
init(AF_INET);
#if defined(POCO_HAVE_IPv6)
else if (family == SocketAddress::IPv6)
init(AF_INET6);
#endif
#if defined(POCO_OS_FAMILY_UNIX)
else if (family == SocketAddress::UNIX_LOCAL)
init(AF_UNIX);
#endif
else throw Poco::InvalidArgumentException("Invalid or unsupported address family passed to StreamSocketImpl");
}
StreamSocketImpl::StreamSocketImpl(poco_socket_t sockfd): SocketImpl(sockfd)
{
}
StreamSocketImpl::~StreamSocketImpl()
{
}
int StreamSocketImpl::sendBytes(const void* buffer, int length, int flags)
{
const char* p = reinterpret_cast<const char*>(buffer);
int remaining = length;
int sent = 0;
bool blocking = getBlocking();
while (remaining > 0)
{
int n = SocketImpl::sendBytes(p, remaining, flags);
poco_assert_dbg (n >= 0);
p += n;
sent += n;
remaining -= n;
if (blocking && remaining > 0)
Poco::Thread::yield();
else
break;
}
return sent;
}
} } // namespace Poco::Net
+67
View File
@@ -0,0 +1,67 @@
//
// StringPartSource.cpp
//
// Library: Net
// Package: Messages
// Module: StringPartSource
//
// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/StringPartSource.h"
namespace Poco {
namespace Net {
StringPartSource::StringPartSource(const std::string& str):
PartSource("text/plain"),
_istr(str)
{
}
StringPartSource::StringPartSource(const std::string& str, const std::string& mediaType):
PartSource(mediaType),
_istr(str)
{
}
StringPartSource::StringPartSource(const std::string& str, const std::string& mediaType, const std::string& filename):
PartSource(mediaType),
_istr(str),
_filename(filename)
{
}
StringPartSource::~StringPartSource()
{
}
std::istream& StringPartSource::stream()
{
return _istr;
}
const std::string& StringPartSource::filename() const
{
return _filename;
}
std::streamsize StringPartSource::getContentLength() const
{
return _istr.str().length();
}
} } // namespace Poco::Net
+243
View File
@@ -0,0 +1,243 @@
//
// TCPServer.cpp
//
// Library: Net
// Package: TCPServer
// Module: TCPServer
//
// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/TCPServer.h"
#include "Poco/Net/TCPServerDispatcher.h"
#include "Poco/Net/TCPServerConnection.h"
#include "Poco/Net/TCPServerConnectionFactory.h"
#include "Poco/Timespan.h"
#include "Poco/Exception.h"
#include "Poco/ErrorHandler.h"
using Poco::ErrorHandler;
namespace Poco {
namespace Net {
//
// TCPServerConnectionFilter
//
TCPServerConnectionFilter::~TCPServerConnectionFilter()
{
}
//
// TCPServer
//
TCPServer::TCPServer(TCPServerConnectionFactory::Ptr pFactory, Poco::UInt16 portNumber, TCPServerParams::Ptr pParams):
_socket(ServerSocket(portNumber)),
_thread(threadName(_socket)),
_stopped(true)
{
Poco::ThreadPool& pool = Poco::ThreadPool::defaultPool();
if (pParams)
{
int toAdd = pParams->getMaxThreads() - pool.capacity();
if (toAdd > 0) pool.addCapacity(toAdd);
}
_pDispatcher = new TCPServerDispatcher(pFactory, pool, pParams);
}
TCPServer::TCPServer(TCPServerConnectionFactory::Ptr pFactory, const ServerSocket& socket, TCPServerParams::Ptr pParams):
_socket(socket),
_thread(threadName(socket)),
_stopped(true)
{
Poco::ThreadPool& pool = Poco::ThreadPool::defaultPool();
if (pParams)
{
int toAdd = pParams->getMaxThreads() - pool.capacity();
if (toAdd > 0) pool.addCapacity(toAdd);
}
_pDispatcher = new TCPServerDispatcher(pFactory, pool, pParams);
}
TCPServer::TCPServer(TCPServerConnectionFactory::Ptr pFactory, Poco::ThreadPool& threadPool, const ServerSocket& socket, TCPServerParams::Ptr pParams):
_socket(socket),
_pDispatcher(new TCPServerDispatcher(pFactory, threadPool, pParams)),
_thread(threadName(socket)),
_stopped(true)
{
}
TCPServer::~TCPServer()
{
try
{
stop();
_pDispatcher->release();
}
catch (...)
{
poco_unexpected();
}
}
const TCPServerParams& TCPServer::params() const
{
return _pDispatcher->params();
}
void TCPServer::start()
{
poco_assert (_stopped);
_stopped = false;
_thread.start(*this);
}
void TCPServer::stop()
{
if (!_stopped)
{
_stopped = true;
_thread.join();
_pDispatcher->stop();
}
}
void TCPServer::run()
{
while (!_stopped)
{
Poco::Timespan timeout(250000);
try
{
if (_socket.poll(timeout, Socket::SELECT_READ))
{
try
{
StreamSocket ss = _socket.acceptConnection();
if (!_pConnectionFilter || _pConnectionFilter->accept(ss))
{
// enable nodelay per default: OSX really needs that
#if defined(POCO_OS_FAMILY_UNIX)
if (ss.address().family() != AddressFamily::UNIX_LOCAL)
#endif
{
ss.setNoDelay(true);
}
_pDispatcher->enqueue(ss);
}
}
catch (Poco::Exception& exc)
{
ErrorHandler::handle(exc);
}
catch (std::exception& exc)
{
ErrorHandler::handle(exc);
}
catch (...)
{
ErrorHandler::handle();
}
}
}
catch (Poco::Exception& exc)
{
ErrorHandler::handle(exc);
// possibly a resource issue since poll() failed;
// give some time to recover before trying again
Poco::Thread::sleep(50);
}
}
}
int TCPServer::currentThreads() const
{
return _pDispatcher->currentThreads();
}
int TCPServer::maxThreads() const
{
return _pDispatcher->maxThreads();
}
int TCPServer::totalConnections() const
{
return _pDispatcher->totalConnections();
}
int TCPServer::currentConnections() const
{
return _pDispatcher->currentConnections();
}
int TCPServer::maxConcurrentConnections() const
{
return _pDispatcher->maxConcurrentConnections();
}
int TCPServer::queuedConnections() const
{
return _pDispatcher->queuedConnections();
}
int TCPServer::refusedConnections() const
{
return _pDispatcher->refusedConnections();
}
void TCPServer::setConnectionFilter(const TCPServerConnectionFilter::Ptr& pConnectionFilter)
{
poco_assert (_stopped);
_pConnectionFilter = pConnectionFilter;
}
std::string TCPServer::threadName(const ServerSocket& socket)
{
#if _WIN32_WCE == 0x0800
// Workaround for WEC2013: only the first call to getsockname()
// succeeds. To mitigate the impact of this bug, do not call
// socket.address(), which calls getsockname(), here.
std::string name("TCPServer");
#pragma message("Using WEC2013 getsockname() workaround in TCPServer::threadName(). Remove when no longer needed.")
#else
std::string name("TCPServer: ");
name.append(socket.address().toString());
#endif
return name;
}
} } // namespace Poco::Net
+60
View File
@@ -0,0 +1,60 @@
//
// TCPServerConnection.cpp
//
// Library: Net
// Package: TCPServer
// Module: TCPServerConnection
//
// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/TCPServerConnection.h"
#include "Poco/Exception.h"
#include "Poco/ErrorHandler.h"
using Poco::Exception;
using Poco::ErrorHandler;
namespace Poco {
namespace Net {
TCPServerConnection::TCPServerConnection(const StreamSocket& socket):
_socket(socket)
{
}
TCPServerConnection::~TCPServerConnection()
{
}
void TCPServerConnection::start()
{
try
{
run();
}
catch (Exception& exc)
{
ErrorHandler::handle(exc);
}
catch (std::exception& exc)
{
ErrorHandler::handle(exc);
}
catch (...)
{
ErrorHandler::handle();
}
}
} } // namespace Poco::Net
+32
View File
@@ -0,0 +1,32 @@
//
// TCPServerConnectionFactory.cpp
//
// Library: Net
// Package: TCPServer
// Module: TCPServerConnectionFactory
//
// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Net/TCPServerConnectionFactory.h"
namespace Poco {
namespace Net {
TCPServerConnectionFactory::TCPServerConnectionFactory()
{
}
TCPServerConnectionFactory::~TCPServerConnectionFactory()
{
}
} } // namespace Poco::Net

Some files were not shown because too many files have changed in this diff Show More