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:
+109
@@ -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
|
||||
Vendored
+687
@@ -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
@@ -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
@@ -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
|
||||
Vendored
+295
@@ -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
@@ -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 << "<";
|
||||
break;
|
||||
case '>':
|
||||
*_pOstr << ">";
|
||||
break;
|
||||
case '"':
|
||||
*_pOstr << """;
|
||||
break;
|
||||
case '&':
|
||||
*_pOstr << "&";
|
||||
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
@@ -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
@@ -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
@@ -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
|
||||
Vendored
+468
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
Vendored
+392
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
Vendored
+65
@@ -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
|
||||
Vendored
+203
@@ -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
@@ -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
|
||||
Vendored
+309
@@ -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
@@ -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
|
||||
@@ -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
|
||||
Vendored
+404
@@ -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
|
||||
Vendored
+56
@@ -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
@@ -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
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
Vendored
+261
@@ -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
@@ -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
@@ -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
|
||||
Vendored
+172
@@ -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
@@ -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
|
||||
Vendored
+135
@@ -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
|
||||
Vendored
+151
@@ -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
@@ -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
|
||||
Vendored
+110
@@ -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
@@ -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
|
||||
Vendored
+147
@@ -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
@@ -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
@@ -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
|
||||
Vendored
+601
@@ -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
@@ -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
|
||||
Vendored
+748
@@ -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
@@ -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
|
||||
Vendored
+221
@@ -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
|
||||
Vendored
+210
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
Vendored
+95
@@ -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
|
||||
Vendored
+71
@@ -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
|
||||
Vendored
+158
@@ -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
@@ -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
|
||||
Vendored
+96
@@ -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 += "<"; break;
|
||||
case '>': html += ">"; break;
|
||||
case '"': html += """; break;
|
||||
case '&': html += "&"; 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
|
||||
Vendored
+55
@@ -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
|
||||
+1814
File diff suppressed because it is too large
Load Diff
+46
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
Vendored
+32
@@ -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
|
||||
Vendored
+58
@@ -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
|
||||
Vendored
+87
@@ -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
|
||||
Vendored
+580
@@ -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
@@ -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
@@ -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
|
||||
Vendored
+117
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
Vendored
+210
@@ -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
@@ -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
@@ -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
|
||||
Vendored
+158
@@ -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
@@ -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
|
||||
Vendored
+467
@@ -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
@@ -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
@@ -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
|
||||
Vendored
+1304
File diff suppressed because it is too large
Load Diff
+105
@@ -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
@@ -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
@@ -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
|
||||
Vendored
+156
@@ -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
|
||||
Vendored
+168
@@ -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
@@ -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
@@ -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
|
||||
Vendored
+243
@@ -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
@@ -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
|
||||
@@ -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
Reference in New Issue
Block a user