From a460bafa702f4298c910d96704e682eb67c5c381 Mon Sep 17 00:00:00 2001 From: Guenter Obiltschnig Date: Tue, 31 Oct 2017 16:53:06 +0100 Subject: [PATCH] merge Unix Domain Sockets support and other changes from develop --- Net/include/Poco/Net/DatagramSocket.h | 25 +- Net/include/Poco/Net/DatagramSocketImpl.h | 2 +- Net/include/Poco/Net/HTTPClientSession.h | 19 ++ Net/include/Poco/Net/HTTPRequest.h | 9 + .../Poco/Net/HTTPRequestHandlerFactory.h | 5 + Net/include/Poco/Net/HTTPResponse.h | 64 ++++- Net/include/Poco/Net/HTTPServerRequest.h | 10 +- Net/include/Poco/Net/HTTPServerRequestImpl.h | 13 +- Net/include/Poco/Net/HTTPSession.h | 12 +- Net/include/Poco/Net/ICMPClient.h | 6 +- Net/include/Poco/Net/ICMPPacket.h | 2 +- Net/include/Poco/Net/ICMPSocket.h | 2 +- Net/include/Poco/Net/ICMPSocketImpl.h | 2 +- Net/include/Poco/Net/IPAddress.h | 102 ++++--- Net/include/Poco/Net/IPAddressImpl.h | 15 +- Net/include/Poco/Net/MessageHeader.h | 5 + Net/include/Poco/Net/MulticastSocket.h | 11 +- Net/include/Poco/Net/NTPClient.h | 4 +- Net/include/Poco/Net/NetException.h | 1 + Net/include/Poco/Net/NetworkInterface.h | 3 +- Net/include/Poco/Net/RawSocket.h | 16 +- Net/include/Poco/Net/RawSocketImpl.h | 2 +- Net/include/Poco/Net/ServerSocket.h | 63 +++++ Net/include/Poco/Net/SocketAddress.h | 126 ++++++++- Net/include/Poco/Net/SocketAddressImpl.h | 96 ++++++- Net/include/Poco/Net/SocketDefs.h | 43 ++- Net/include/Poco/Net/SocketImpl.h | 36 ++- Net/include/Poco/Net/StreamSocket.h | 4 +- Net/include/Poco/Net/StreamSocketImpl.h | 2 +- Net/include/Poco/Net/TCPServer.h | 57 +++- Net/include/Poco/Net/WebSocket.h | 16 ++ Net/include/Poco/Net/WebSocketImpl.h | 8 + Net/src/DatagramSocket.cpp | 8 +- Net/src/DatagramSocketImpl.cpp | 11 +- Net/src/HTTPClientSession.cpp | 79 ++++-- Net/src/HTTPRequest.cpp | 17 ++ Net/src/HTTPResponse.cpp | 89 +++++- Net/src/HTTPServerConnection.cpp | 2 +- Net/src/HTTPServerRequestImpl.cpp | 17 +- Net/src/HTTPSession.cpp | 27 +- Net/src/HTTPStreamFactory.cpp | 2 +- Net/src/ICMPClient.cpp | 2 +- Net/src/IPAddress.cpp | 48 +++- Net/src/IPAddressImpl.cpp | 6 +- Net/src/MessageHeader.cpp | 141 +++++++++- Net/src/MulticastSocket.cpp | 13 +- Net/src/NetException.cpp | 3 +- Net/src/NetworkInterface.cpp | 16 +- Net/src/RawSocket.cpp | 8 +- Net/src/RawSocketImpl.cpp | 6 +- Net/src/ServerSocket.cpp | 36 +++ Net/src/Socket.cpp | 4 +- Net/src/SocketAddress.cpp | 259 +++++++++++++++--- Net/src/SocketAddressImpl.cpp | 64 +++++ Net/src/SocketImpl.cpp | 104 ++++--- Net/src/StreamSocket.cpp | 2 +- Net/src/StreamSocketImpl.cpp | 10 +- Net/src/TCPServer.cpp | 38 ++- Net/src/WebSocket.cpp | 9 +- Net/src/WebSocketImpl.cpp | 137 +++++---- Net/testsuite/src/DNSTest.cpp | 8 +- Net/testsuite/src/DatagramSocketTest.cpp | 24 +- Net/testsuite/src/DatagramSocketTest.h | 1 + Net/testsuite/src/DialogSocketTest.cpp | 2 +- Net/testsuite/src/EchoServer.cpp | 10 + Net/testsuite/src/EchoServer.h | 3 + Net/testsuite/src/FTPClientSessionTest.cpp | 30 +- Net/testsuite/src/FTPStreamFactoryTest.cpp | 10 +- Net/testsuite/src/HTMLFormTest.cpp | 40 +++ Net/testsuite/src/HTMLFormTest.h | 2 + Net/testsuite/src/HTTPClientSessionTest.cpp | 69 ++++- Net/testsuite/src/HTTPClientSessionTest.h | 2 + Net/testsuite/src/HTTPResponseTest.cpp | 4 +- Net/testsuite/src/HTTPServerTest.cpp | 28 +- Net/testsuite/src/HTTPStreamFactoryTest.cpp | 10 +- Net/testsuite/src/HTTPTestServer.cpp | 31 +++ Net/testsuite/src/ICMPClientTest.cpp | 4 +- Net/testsuite/src/MailMessageTest.cpp | 36 +++ Net/testsuite/src/MailMessageTest.h | 1 + Net/testsuite/src/MessageHeaderTest.cpp | 18 ++ Net/testsuite/src/MessageHeaderTest.h | 1 + Net/testsuite/src/MulticastSocketTest.cpp | 2 +- Net/testsuite/src/NetworkInterfaceTest.cpp | 14 +- Net/testsuite/src/POP3ClientSessionTest.cpp | 16 +- Net/testsuite/src/RawSocketTest.cpp | 4 +- Net/testsuite/src/SMTPClientSessionTest.cpp | 14 +- Net/testsuite/src/SocketAddressTest.cpp | 61 ++++- Net/testsuite/src/SocketAddressTest.h | 1 + Net/testsuite/src/SocketReactorTest.cpp | 8 +- Net/testsuite/src/SocketStreamTest.cpp | 6 +- Net/testsuite/src/SocketTest.cpp | 54 +++- Net/testsuite/src/SocketTest.h | 1 + Net/testsuite/src/SyslogTest.cpp | 6 +- Net/testsuite/src/TCPServerTest.cpp | 44 ++- Net/testsuite/src/TCPServerTest.h | 1 + Net/testsuite/src/WebSocketTest.cpp | 62 ++++- Net/testsuite/src/WebSocketTest.h | 2 + 97 files changed, 2094 insertions(+), 475 deletions(-) diff --git a/Net/include/Poco/Net/DatagramSocket.h b/Net/include/Poco/Net/DatagramSocket.h index 215e5e87b..17d025315 100644 --- a/Net/include/Poco/Net/DatagramSocket.h +++ b/Net/include/Poco/Net/DatagramSocket.h @@ -32,9 +32,16 @@ class Net_API DatagramSocket: public Socket { public: DatagramSocket(); - /// Creates an unconnected IPv4 datagram socket. + /// Creates an unconnected, unbound datagram socket. + /// + /// Before the datagram socket can be used, bind(), + /// bind6() or connect() must be called. + /// + /// Notice: The behavior of this constructor has changed + /// in release 2.0. Previously, the constructor created + /// an unbound IPv4 datagram socket. - explicit DatagramSocket(IPAddress::Family family); + explicit DatagramSocket(SocketAddress::Family family); /// Creates an unconnected datagram socket. /// /// The socket will be created for the @@ -80,6 +87,20 @@ public: /// /// Calls to connect cannot() come before calls to bind(). + void bind(const SocketAddress& address, bool reuseAddress, bool reusePort); + /// Bind a local address to the socket. + /// + /// This is usually only done when establishing a server + /// socket. + /// + /// If reuseAddress is true, sets the SO_REUSEADDR + /// socket option. + /// + /// If reusePort is true, sets the SO_REUSEPORT + /// socket option. + /// + /// Calls to connect cannot() come before calls to bind(). + int sendBytes(const void* buffer, int length, int flags = 0); /// Sends the contents of the given buffer through /// the socket. diff --git a/Net/include/Poco/Net/DatagramSocketImpl.h b/Net/include/Poco/Net/DatagramSocketImpl.h index a9a5cce6c..f9d280aa1 100644 --- a/Net/include/Poco/Net/DatagramSocketImpl.h +++ b/Net/include/Poco/Net/DatagramSocketImpl.h @@ -33,7 +33,7 @@ public: DatagramSocketImpl(); /// Creates an unconnected, unbound datagram socket. - explicit DatagramSocketImpl(IPAddress::Family family); + explicit DatagramSocketImpl(SocketAddress::Family family); /// Creates an unconnected datagram socket. /// /// The socket will be created for the diff --git a/Net/include/Poco/Net/HTTPClientSession.h b/Net/include/Poco/Net/HTTPClientSession.h index 7cb48e537..b3a33b4e8 100644 --- a/Net/include/Poco/Net/HTTPClientSession.h +++ b/Net/include/Poco/Net/HTTPClientSession.h @@ -225,6 +225,24 @@ public: /// to ensure a new connection will be set up /// for the next request. + virtual bool peekResponse(HTTPResponse& response); + /// If the request contains a "Expect: 100-continue" header, + /// (see HTTPRequest::setExpectContinue()) this method can be + /// used to check whether the server has sent a 100 Continue response + /// before continuing with the request, i.e. sending the request body, + /// after calling sendRequest(). + /// + /// Returns true if the server has responded with 100 Continue, + /// otherwise false. The HTTPResponse object contains the + /// response sent by the server. + /// + /// In any case, receiveResponse() must be called afterwards as well in + /// order to complete the request. The same HTTPResponse object + /// passed to peekResponse() must also be passed to receiveResponse(). + /// + /// This method should only be called if the request contains + /// a "Expect: 100-continue" header. + void reset(); /// Resets the session and closes the socket. /// @@ -289,6 +307,7 @@ private: bool _reconnect; bool _mustReconnect; bool _expectResponseBody; + bool _responseReceived; Poco::SharedPtr _pRequestStream; Poco::SharedPtr _pResponseStream; diff --git a/Net/include/Poco/Net/HTTPRequest.h b/Net/include/Poco/Net/HTTPRequest.h index 474f400b1..817a74dc4 100644 --- a/Net/include/Poco/Net/HTTPRequest.h +++ b/Net/include/Poco/Net/HTTPRequest.h @@ -103,6 +103,14 @@ public: /// Sets the authentication scheme and information for /// this request. + bool getExpectContinue() const; + /// Returns true if the request contains an + /// "Expect: 100-continue" header. + + void setExpectContinue(bool expectContinue); + /// Adds a "Expect: 100-continue" header to the request if + /// expectContinue is true, otherwise removes the Expect header. + bool hasProxyCredentials() const; /// Returns true iff the request contains proxy authentication /// information in the form of an Proxy-Authorization header. @@ -141,6 +149,7 @@ public: static const std::string AUTHORIZATION; static const std::string PROXY_AUTHORIZATION; static const std::string UPGRADE; + static const std::string EXPECT; protected: void getCredentials(const std::string& header, std::string& scheme, std::string& authInfo) const; diff --git a/Net/include/Poco/Net/HTTPRequestHandlerFactory.h b/Net/include/Poco/Net/HTTPRequestHandlerFactory.h index 6da6e487a..421c46501 100644 --- a/Net/include/Poco/Net/HTTPRequestHandlerFactory.h +++ b/Net/include/Poco/Net/HTTPRequestHandlerFactory.h @@ -54,6 +54,11 @@ public: /// The method should inspect the given HTTPServerRequest object (e.g., method /// and URI) and create an appropriate HTTPRequestHandler object to handle the /// request. + /// + /// If the request contains a "Expect: 100-continue" header, it's possible + /// to prevent the server from sending the default 100 Continue response + /// by setting the status of the response object that can be obtained through + /// the request object (request.response()) to something other than 200 OK. protected: Poco::BasicEvent serverStopped; diff --git a/Net/include/Poco/Net/HTTPResponse.h b/Net/include/Poco/Net/HTTPResponse.h index 7ecb74cc3..fd6eb81c5 100644 --- a/Net/include/Poco/Net/HTTPResponse.h +++ b/Net/include/Poco/Net/HTTPResponse.h @@ -45,6 +45,7 @@ public: { HTTP_CONTINUE = 100, HTTP_SWITCHING_PROTOCOLS = 101, + HTTP_PROCESSING = 102, HTTP_OK = 200, HTTP_CREATED = 201, HTTP_ACCEPTED = 202, @@ -52,14 +53,19 @@ public: HTTP_NO_CONTENT = 204, HTTP_RESET_CONTENT = 205, HTTP_PARTIAL_CONTENT = 206, + HTTP_MULTI_STATUS = 207, + HTTP_ALREADY_REPORTED = 208, + HTTP_IM_USED = 226, HTTP_MULTIPLE_CHOICES = 300, HTTP_MOVED_PERMANENTLY = 301, HTTP_FOUND = 302, HTTP_SEE_OTHER = 303, HTTP_NOT_MODIFIED = 304, - HTTP_USEPROXY = 305, + HTTP_USE_PROXY = 305, + HTTP_USEPROXY = 305, /// @deprecated // UNUSED: 306 HTTP_TEMPORARY_REDIRECT = 307, + HTTP_PERMANENT_REDIRECT = 308, HTTP_BAD_REQUEST = 400, HTTP_UNAUTHORIZED = 401, HTTP_PAYMENT_REQUIRED = 402, @@ -73,17 +79,36 @@ public: HTTP_GONE = 410, HTTP_LENGTH_REQUIRED = 411, HTTP_PRECONDITION_FAILED = 412, - HTTP_REQUESTENTITYTOOLARGE = 413, - HTTP_REQUESTURITOOLONG = 414, - HTTP_UNSUPPORTEDMEDIATYPE = 415, + HTTP_REQUEST_ENTITY_TOO_LARGE = 413, + HTTP_REQUESTENTITYTOOLARGE = 413, /// @deprecated + HTTP_REQUEST_URI_TOO_LONG = 414, + HTTP_REQUESTURITOOLONG = 414, /// @deprecated + HTTP_UNSUPPORTED_MEDIA_TYPE = 415, + HTTP_UNSUPPORTEDMEDIATYPE = 415, /// @deprecated HTTP_REQUESTED_RANGE_NOT_SATISFIABLE = 416, HTTP_EXPECTATION_FAILED = 417, + HTTP_IM_A_TEAPOT = 418, + HTTP_ENCHANCE_YOUR_CALM = 420, + HTTP_MISDIRECTED_REQUEST = 421, + HTTP_UNPROCESSABLE_ENTITY = 422, + HTTP_LOCKED = 423, + HTTP_FAILED_DEPENDENCY = 424, + HTTP_UPGRADE_REQUIRED = 426, + HTTP_PRECONDITION_REQUIRED = 428, + HTTP_TOO_MANY_REQUESTS = 429, + HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE = 431, + HTTP_UNAVAILABLE_FOR_LEGAL_REASONS = 451, HTTP_INTERNAL_SERVER_ERROR = 500, HTTP_NOT_IMPLEMENTED = 501, HTTP_BAD_GATEWAY = 502, HTTP_SERVICE_UNAVAILABLE = 503, HTTP_GATEWAY_TIMEOUT = 504, - HTTP_VERSION_NOT_SUPPORTED = 505 + HTTP_VERSION_NOT_SUPPORTED = 505, + HTTP_VARIANT_ALSO_NEGOTIATES = 506, + HTTP_INSUFFICIENT_STORAGE = 507, + HTTP_LOOP_DETECTED = 508, + HTTP_NOT_EXTENDED = 510, + HTTP_NETWORK_AUTHENTICATION_REQUIRED = 511 }; HTTPResponse(); @@ -169,6 +194,7 @@ public: static const std::string HTTP_REASON_CONTINUE; static const std::string HTTP_REASON_SWITCHING_PROTOCOLS; + static const std::string HTTP_REASON_PROCESSING; static const std::string HTTP_REASON_OK; static const std::string HTTP_REASON_CREATED; static const std::string HTTP_REASON_ACCEPTED; @@ -176,13 +202,17 @@ public: static const std::string HTTP_REASON_NO_CONTENT; static const std::string HTTP_REASON_RESET_CONTENT; static const std::string HTTP_REASON_PARTIAL_CONTENT; + static const std::string HTTP_REASON_MULTI_STATUS; + static const std::string HTTP_REASON_ALREADY_REPORTED; + static const std::string HTTP_REASON_IM_USED; static const std::string HTTP_REASON_MULTIPLE_CHOICES; static const std::string HTTP_REASON_MOVED_PERMANENTLY; static const std::string HTTP_REASON_FOUND; static const std::string HTTP_REASON_SEE_OTHER; static const std::string HTTP_REASON_NOT_MODIFIED; - static const std::string HTTP_REASON_USEPROXY; + static const std::string HTTP_REASON_USE_PROXY; static const std::string HTTP_REASON_TEMPORARY_REDIRECT; + static const std::string HTTP_REASON_PERMANENT_REDIRECT; static const std::string HTTP_REASON_BAD_REQUEST; static const std::string HTTP_REASON_UNAUTHORIZED; static const std::string HTTP_REASON_PAYMENT_REQUIRED; @@ -196,17 +226,33 @@ public: static const std::string HTTP_REASON_GONE; static const std::string HTTP_REASON_LENGTH_REQUIRED; static const std::string HTTP_REASON_PRECONDITION_FAILED; - static const std::string HTTP_REASON_REQUESTENTITYTOOLARGE; - static const std::string HTTP_REASON_REQUESTURITOOLONG; - static const std::string HTTP_REASON_UNSUPPORTEDMEDIATYPE; + static const std::string HTTP_REASON_REQUEST_ENTITY_TOO_LARGE; + static const std::string HTTP_REASON_REQUEST_URI_TOO_LONG; + static const std::string HTTP_REASON_UNSUPPORTED_MEDIA_TYPE; static const std::string HTTP_REASON_REQUESTED_RANGE_NOT_SATISFIABLE; static const std::string HTTP_REASON_EXPECTATION_FAILED; + static const std::string HTTP_REASON_IM_A_TEAPOT; + static const std::string HTTP_REASON_ENCHANCE_YOUR_CALM; + static const std::string HTTP_REASON_MISDIRECTED_REQUEST; + static const std::string HTTP_REASON_UNPROCESSABLE_ENTITY; + static const std::string HTTP_REASON_LOCKED; + static const std::string HTTP_REASON_FAILED_DEPENDENCY; + static const std::string HTTP_REASON_UPGRADE_REQUIRED; + static const std::string HTTP_REASON_PRECONDITION_REQUIRED; + static const std::string HTTP_REASON_TOO_MANY_REQUESTS; + static const std::string HTTP_REASON_REQUEST_HEADER_FIELDS_TOO_LARGE; + static const std::string HTTP_REASON_UNAVAILABLE_FOR_LEGAL_REASONS; static const std::string HTTP_REASON_INTERNAL_SERVER_ERROR; static const std::string HTTP_REASON_NOT_IMPLEMENTED; static const std::string HTTP_REASON_BAD_GATEWAY; static const std::string HTTP_REASON_SERVICE_UNAVAILABLE; static const std::string HTTP_REASON_GATEWAY_TIMEOUT; static const std::string HTTP_REASON_VERSION_NOT_SUPPORTED; + static const std::string HTTP_REASON_VARIANT_ALSO_NEGOTIATES; + static const std::string HTTP_REASON_INSUFFICIENT_STORAGE; + static const std::string HTTP_REASON_LOOP_DETECTED; + static const std::string HTTP_REASON_NOT_EXTENDED; + static const std::string HTTP_REASON_NETWORK_AUTHENTICATION_REQUIRED; static const std::string HTTP_REASON_UNKNOWN; static const std::string DATE; diff --git a/Net/include/Poco/Net/HTTPServerRequest.h b/Net/include/Poco/Net/HTTPServerRequest.h index b1566985d..69ffeaec0 100644 --- a/Net/include/Poco/Net/HTTPServerRequest.h +++ b/Net/include/Poco/Net/HTTPServerRequest.h @@ -54,10 +54,6 @@ public: /// The stream must be valid until the HTTPServerRequest /// object is destroyed. - virtual bool expectContinue() const = 0; - /// Returns true if the client expects a - /// 100 Continue response. - virtual const SocketAddress& clientAddress() const = 0; /// Returns the client's address. @@ -69,6 +65,12 @@ public: virtual HTTPServerResponse& response() const = 0; /// Returns a reference to the associated response. + + virtual bool secure() const = 0; + /// Returns true if the request is using a secure + /// connection. Returns false if no secure connection + /// is used, or if it is not known whether a secure + /// connection is used. }; diff --git a/Net/include/Poco/Net/HTTPServerRequestImpl.h b/Net/include/Poco/Net/HTTPServerRequestImpl.h index 8bfb5ba04..419adbb5e 100644 --- a/Net/include/Poco/Net/HTTPServerRequestImpl.h +++ b/Net/include/Poco/Net/HTTPServerRequestImpl.h @@ -57,10 +57,6 @@ public: /// The stream is valid until the HTTPServerRequestImpl /// object is destroyed. - bool expectContinue() const; - /// Returns true if the client expects a - /// 100 Continue response. - const SocketAddress& clientAddress() const; /// Returns the client's address. @@ -73,6 +69,12 @@ public: HTTPServerResponse& response() const; /// Returns a reference to the associated response. + bool secure() const; + /// Returns true if the request is using a secure + /// connection. Returns false if no secure connection + /// is used, or if it is not known whether a secure + /// connection is used. + StreamSocket& socket(); /// Returns a reference to the underlying socket. @@ -83,9 +85,6 @@ public: HTTPServerSession& session(); /// Returns the underlying HTTPServerSession. -protected: - static const std::string EXPECT; - private: HTTPServerResponseImpl& _response; HTTPServerSession& _session; diff --git a/Net/include/Poco/Net/HTTPSession.h b/Net/include/Poco/Net/HTTPSession.h index 9a226ff1c..666f6f626 100644 --- a/Net/include/Poco/Net/HTTPSession.h +++ b/Net/include/Poco/Net/HTTPSession.h @@ -55,6 +55,9 @@ public: void setTimeout(const Poco::Timespan& timeout); /// Sets the timeout for the HTTP session. + void setTimeout(const Poco::Timespan& connectionTimeout, const Poco::Timespan& sendTimeout, const Poco::Timespan& receiveTimeout); + /// Sets different timeouts for the HTTP session. + Poco::Timespan getTimeout() const; /// Returns the timeout for the HTTP session. @@ -178,7 +181,8 @@ protected: private: enum { - HTTP_DEFAULT_TIMEOUT = 60000000 + HTTP_DEFAULT_TIMEOUT = 60000000, + HTTP_DEFAULT_CONNECTION_TIMEOUT = 30000000 }; HTTPSession(const HTTPSession&); @@ -189,7 +193,9 @@ private: char* _pCurrent; char* _pEnd; bool _keepAlive; - Poco::Timespan _timeout; + Poco::Timespan _connectionTimeout; + Poco::Timespan _receiveTimeout; + Poco::Timespan _sendTimeout; Poco::Exception* _pException; Poco::Any _data; @@ -211,7 +217,7 @@ inline bool HTTPSession::getKeepAlive() const inline Poco::Timespan HTTPSession::getTimeout() const { - return _timeout; + return _receiveTimeout; } diff --git a/Net/include/Poco/Net/ICMPClient.h b/Net/include/Poco/Net/ICMPClient.h index 623c12b8c..344404e69 100644 --- a/Net/include/Poco/Net/ICMPClient.h +++ b/Net/include/Poco/Net/ICMPClient.h @@ -44,7 +44,7 @@ public: mutable Poco::BasicEvent pingError; mutable Poco::BasicEvent pingEnd; - explicit ICMPClient(IPAddress::Family family); + explicit ICMPClient(SocketAddress::Family family); /// Creates an ICMP client. ~ICMPClient(); @@ -62,7 +62,7 @@ public: /// /// Returns the number of valid replies. - static int ping(SocketAddress& address, IPAddress::Family family, int repeat = 1); + static int ping(SocketAddress& address, SocketAddress::Family family, int repeat = 1); /// Pings the specified address [repeat] times. /// Notifications are not posted for events. /// @@ -75,7 +75,7 @@ public: /// Returns the number of valid replies. private: - mutable IPAddress::Family _family; + mutable SocketAddress::Family _family; }; diff --git a/Net/include/Poco/Net/ICMPPacket.h b/Net/include/Poco/Net/ICMPPacket.h index 1781c8464..52d0e87f8 100644 --- a/Net/include/Poco/Net/ICMPPacket.h +++ b/Net/include/Poco/Net/ICMPPacket.h @@ -31,7 +31,7 @@ class Net_API ICMPPacket /// This class is the ICMP packet abstraction. { public: - ICMPPacket(IPAddress::Family family, int dataSize = 48); + ICMPPacket(SocketAddress::Family family, int dataSize = 48); /// Creates an ICMPPacket of specified family. ~ICMPPacket(); diff --git a/Net/include/Poco/Net/ICMPSocket.h b/Net/include/Poco/Net/ICMPSocket.h index d51bf7ecf..75e049b38 100644 --- a/Net/include/Poco/Net/ICMPSocket.h +++ b/Net/include/Poco/Net/ICMPSocket.h @@ -31,7 +31,7 @@ class Net_API ICMPSocket: public Socket /// ICMP client socket. { public: - ICMPSocket(IPAddress::Family family, int dataSize = 48, int ttl = 128, int timeout = 5000000); + ICMPSocket(SocketAddress::Family family, int dataSize = 48, int ttl = 128, int timeout = 5000000); /// Creates an unconnected ICMP socket. /// /// The socket will be created for the diff --git a/Net/include/Poco/Net/ICMPSocketImpl.h b/Net/include/Poco/Net/ICMPSocketImpl.h index 13625e2d7..98ba9a225 100644 --- a/Net/include/Poco/Net/ICMPSocketImpl.h +++ b/Net/include/Poco/Net/ICMPSocketImpl.h @@ -32,7 +32,7 @@ class Net_API ICMPSocketImpl: public RawSocketImpl /// This class implements an ICMP socket. { public: - ICMPSocketImpl(IPAddress::Family family, int dataSize, int ttl, int timeout); + ICMPSocketImpl(SocketAddress::Family family, int dataSize, int ttl, int timeout); /// Creates an unconnected ICMP socket. /// /// The socket will be created for the given address family. diff --git a/Net/include/Poco/Net/IPAddress.h b/Net/include/Poco/Net/IPAddress.h index d6beb6842..c7f1f1a43 100644 --- a/Net/include/Poco/Net/IPAddress.h +++ b/Net/include/Poco/Net/IPAddress.h @@ -24,6 +24,7 @@ #include "Poco/AutoPtr.h" #include "Poco/Exception.h" #include +#include namespace Poco { @@ -55,14 +56,14 @@ class Net_API IPAddress public: typedef std::vector List; - enum Family - /// Possible address families for IP addresses. - { - IPv4 = Poco::Net::Impl::IPAddressImpl::IPv4 -#ifdef POCO_HAVE_IPv6 - ,IPv6 = Poco::Net::Impl::IPAddressImpl::IPv6 + // The following declarations keep the Family type + // backwards compatible with the previously used + // enum declaration. + typedef AddressFamily::Family Family; + static const Family IPv4 = AddressFamily::IPv4; +#if defined(POCO_HAVE_IPv6) + static const Family IPv6 = AddressFamily::IPv6; #endif - }; IPAddress(); /// Creates a wildcard (zero) IPv4 IPAddress. @@ -371,13 +372,15 @@ private: #endif Ptr pImpl() const; + void newIPv4(); void newIPv4(const void* hostAddr); + void newIPv4(unsigned prefix); +#if defined(POCO_HAVE_IPv6) + void newIPv6(); void newIPv6(const void* hostAddr); void newIPv6(const void* hostAddr, Poco::UInt32 scope); - void newIPv4(unsigned prefix); void newIPv6(unsigned prefix); - void newIPv4(); - void newIPv6(); +#endif void destruct(); #ifdef POCO_HAVE_ALIGNMENT @@ -394,7 +397,11 @@ private: AlignerType aligner; } #else // !POCO_ENABLE_CPP11 - AlignedCharArrayUnion + #if defined(POCO_HAVE_IPv6) + AlignedCharArrayUnion + #else + AlignedCharArrayUnion + #endif #endif // POCO_ENABLE_CPP11 _memory; #else // !POCO_HAVE_ALIGNMENT @@ -406,6 +413,8 @@ private: // // inlines // + + inline void IPAddress::destruct() { #ifdef POCO_HAVE_ALIGNMENT @@ -425,6 +434,16 @@ inline IPAddress::Ptr IPAddress::pImpl() const } +inline void IPAddress::newIPv4() +{ +#ifdef POCO_HAVE_ALIGNMENT + new (storage()) Poco::Net::Impl::IPv4AddressImpl; +#else + _pImpl = new Poco::Net::Impl::IPv4AddressImpl; +#endif +} + + inline void IPAddress::newIPv4(const void* hostAddr) { #ifdef POCO_HAVE_ALIGNMENT @@ -435,6 +454,29 @@ inline void IPAddress::newIPv4(const void* hostAddr) } +inline void IPAddress::newIPv4(unsigned prefix) +{ +#ifdef POCO_HAVE_ALIGNMENT + new (storage()) Poco::Net::Impl::IPv4AddressImpl(prefix); +#else + _pImpl = new Poco::Net::Impl::IPv4AddressImpl(prefix); +#endif +} + + +#if defined(POCO_HAVE_IPv6) + + +inline void IPAddress::newIPv6() +{ +#ifdef POCO_HAVE_ALIGNMENT + new (storage()) Poco::Net::Impl::IPv6AddressImpl; +#else + _pImpl = new Poco::Net::Impl::IPv6AddressImpl; +#endif +} + + inline void IPAddress::newIPv6(const void* hostAddr) { #ifdef POCO_HAVE_ALIGNMENT @@ -455,16 +497,6 @@ inline void IPAddress::newIPv6(const void* hostAddr, Poco::UInt32 scope) } -inline void IPAddress::newIPv4(unsigned prefix) -{ -#ifdef POCO_HAVE_ALIGNMENT - new (storage()) Poco::Net::Impl::IPv4AddressImpl(prefix); -#else - _pImpl = new Poco::Net::Impl::IPv4AddressImpl(prefix); -#endif -} - - inline void IPAddress::newIPv6(unsigned prefix) { #ifdef POCO_HAVE_ALIGNMENT @@ -475,24 +507,7 @@ inline void IPAddress::newIPv6(unsigned prefix) } -inline void IPAddress::newIPv4() -{ -#ifdef POCO_HAVE_ALIGNMENT - new (storage()) Poco::Net::Impl::IPv4AddressImpl; -#else - _pImpl = new Poco::Net::Impl::IPv4AddressImpl; -#endif -} - - -inline void IPAddress::newIPv6() -{ -#ifdef POCO_HAVE_ALIGNMENT - new (storage()) Poco::Net::Impl::IPv6AddressImpl; -#else - _pImpl = new Poco::Net::Impl::IPv6AddressImpl; -#endif -} +#endif // POCO_HAVE_IPv6 #ifdef POCO_HAVE_ALIGNMENT @@ -503,11 +518,12 @@ inline char* IPAddress::storage() #endif -BinaryWriter& operator << (BinaryWriter& writer, const IPAddress& value); -BinaryReader& operator >> (BinaryReader& reader, IPAddress& value); - - } } // namespace Poco::Net +Net_API Poco::BinaryWriter& operator << (Poco::BinaryWriter& writer, const Poco::Net::IPAddress& value); +Net_API Poco::BinaryReader& operator >> (Poco::BinaryReader& reader, Poco::Net::IPAddress& value); +Net_API std::ostream& operator << (std::ostream& ostr, const Poco::Net::IPAddress& addr); + + #endif // Net_IPAddress_INCLUDED diff --git a/Net/include/Poco/Net/IPAddressImpl.h b/Net/include/Poco/Net/IPAddressImpl.h index f5eb6e4c8..d8d56f55b 100644 --- a/Net/include/Poco/Net/IPAddressImpl.h +++ b/Net/include/Poco/Net/IPAddressImpl.h @@ -37,14 +37,7 @@ class IPAddressImpl #endif { public: - enum Family - /// Possible address families for IP addresses. - { - IPv4 -#ifdef POCO_HAVE_IPv6 - ,IPv6 -#endif - }; + typedef AddressFamily::Family Family; virtual ~IPAddressImpl(); @@ -129,6 +122,9 @@ private: }; +#if defined(POCO_HAVE_IPv6) + + // // IPv6AddressImpl // @@ -179,6 +175,9 @@ private: }; +#endif // POCO_HAVE_IPv6 + + } } } // namespace Poco::Net::Impl diff --git a/Net/include/Poco/Net/MessageHeader.h b/Net/include/Poco/Net/MessageHeader.h index 22f9c6c76..f36ad51e6 100644 --- a/Net/include/Poco/Net/MessageHeader.h +++ b/Net/include/Poco/Net/MessageHeader.h @@ -145,6 +145,11 @@ public: /// appended to result, enclosed in double-quotes. /// Otherwise, the value is appended to result as-is. + static void decodeRFC2047(const std::string& ins, std::string& outs, const std::string& charset = "UTF-8"); + static std::string decodeWord(const std::string& text, const std::string& charset = "UTF-8"); + /// Decode RFC2047 string. + + private: enum Limits /// Limits for basic sanity checks when reading a header diff --git a/Net/include/Poco/Net/MulticastSocket.h b/Net/include/Poco/Net/MulticastSocket.h index d4117ac26..6ae465775 100644 --- a/Net/include/Poco/Net/MulticastSocket.h +++ b/Net/include/Poco/Net/MulticastSocket.h @@ -39,9 +39,16 @@ class Net_API MulticastSocket: public DatagramSocket { public: MulticastSocket(); - /// Creates the multicast socket. + /// Creates an unconnected, unbound multicast socket. + /// + /// Before the multicast socket can be used, bind(), + /// bind6() or connect() must be called. + /// + /// Notice: The behavior of this constructor has changed + /// in release 2.0. Previously, the constructor created + /// an unbound IPv4 multicast socket. - explicit MulticastSocket(IPAddress::Family family); + explicit MulticastSocket(SocketAddress::Family family); /// Creates an unconnected datagram socket. /// /// The socket will be created for the diff --git a/Net/include/Poco/Net/NTPClient.h b/Net/include/Poco/Net/NTPClient.h index 1c1ad12e2..044a486a7 100644 --- a/Net/include/Poco/Net/NTPClient.h +++ b/Net/include/Poco/Net/NTPClient.h @@ -34,7 +34,7 @@ class Net_API NTPClient public: mutable Poco::BasicEvent response; - explicit NTPClient(IPAddress::Family family, int timeout = 3000000); + explicit NTPClient(SocketAddress::Family family, int timeout = 3000000); /// Creates an NTP client. ~NTPClient(); @@ -53,7 +53,7 @@ public: /// Returns the number of valid replies. private: - mutable IPAddress::Family _family; + mutable SocketAddress::Family _family; int _timeout; }; diff --git a/Net/include/Poco/Net/NetException.h b/Net/include/Poco/Net/NetException.h index 9b076e730..92bb3ed91 100644 --- a/Net/include/Poco/Net/NetException.h +++ b/Net/include/Poco/Net/NetException.h @@ -51,6 +51,7 @@ POCO_DECLARE_EXCEPTION(Net_API, NTPException, NetException) POCO_DECLARE_EXCEPTION(Net_API, HTMLFormException, NetException) POCO_DECLARE_EXCEPTION(Net_API, WebSocketException, NetException) POCO_DECLARE_EXCEPTION(Net_API, UnsupportedFamilyException, NetException) +POCO_DECLARE_EXCEPTION(Net_API, AddressFamilyMismatchException, NetException) } } // namespace Poco::Net diff --git a/Net/include/Poco/Net/NetworkInterface.h b/Net/include/Poco/Net/NetworkInterface.h index 42d367069..68abae051 100644 --- a/Net/include/Poco/Net/NetworkInterface.h +++ b/Net/include/Poco/Net/NetworkInterface.h @@ -248,8 +248,7 @@ public: /// Returns the NetworkInterface for the given interface index. /// /// Throws an InterfaceNotFoundException if an interface - /// with the given index does not exist (or IPv6 is not - /// available). + /// with the given index does not exist. static List list(bool ipOnly = true, bool upOnly = true); /// Returns a list with all network interfaces diff --git a/Net/include/Poco/Net/RawSocket.h b/Net/include/Poco/Net/RawSocket.h index ff9f0e640..3638b20e4 100644 --- a/Net/include/Poco/Net/RawSocket.h +++ b/Net/include/Poco/Net/RawSocket.h @@ -34,7 +34,7 @@ public: RawSocket(); /// Creates an unconnected IPv4 raw socket. - RawSocket(IPAddress::Family family, int proto = IPPROTO_RAW); + RawSocket(SocketAddress::Family family, int proto = IPPROTO_RAW); /// Creates an unconnected raw socket. /// /// The socket will be created for the @@ -80,6 +80,20 @@ public: /// /// Calls to connect() cannot come before calls to bind(). + void bind(const SocketAddress& address, bool reuseAddress, bool reusePort); + /// Bind a local address to the socket. + /// + /// This is usually only done when establishing a server + /// socket. + /// + /// If reuseAddress is true, sets the SO_REUSEADDR + /// socket option. + /// + /// If reusePort is true, sets the SO_REUSEPORT + /// socket option. + /// + /// Calls to connect() cannot come before calls to bind(). + int sendBytes(const void* buffer, int length, int flags = 0); /// Sends the contents of the given buffer through /// the socket. diff --git a/Net/include/Poco/Net/RawSocketImpl.h b/Net/include/Poco/Net/RawSocketImpl.h index 0b4c71bc1..df10b6458 100644 --- a/Net/include/Poco/Net/RawSocketImpl.h +++ b/Net/include/Poco/Net/RawSocketImpl.h @@ -33,7 +33,7 @@ public: RawSocketImpl(); /// Creates an unconnected IPv4 raw socket with IPPROTO_RAW. - RawSocketImpl(IPAddress::Family family, int proto = IPPROTO_RAW); + RawSocketImpl(SocketAddress::Family family, int proto = IPPROTO_RAW); /// Creates an unconnected raw socket. /// /// The socket will be created for the diff --git a/Net/include/Poco/Net/ServerSocket.h b/Net/include/Poco/Net/ServerSocket.h index e3cfc8c68..d8aca6790 100644 --- a/Net/include/Poco/Net/ServerSocket.h +++ b/Net/include/Poco/Net/ServerSocket.h @@ -80,6 +80,19 @@ public: /// If reuseAddress is true, sets the SO_REUSEADDR /// socket option. + virtual void bind(const SocketAddress& address, bool reuseAddress, bool reusePort); + /// Binds a local address to the socket. + /// + /// This is usually only done when establishing a server + /// socket. TCP clients should not bind a socket to a + /// specific address. + /// + /// If reuseAddress is true, sets the SO_REUSEADDR + /// socket option. + /// + /// If reuseAddress is true, sets the SO_REUSEPORT + /// socket option. + virtual void bind(Poco::UInt16 port, bool reuseAddress = false); /// Binds a local port to the socket. /// @@ -89,6 +102,18 @@ public: /// If reuseAddress is true, sets the SO_REUSEADDR /// socket option. + virtual void bind(Poco::UInt16 port, bool reuseAddress, bool reusePort); + /// Binds a local port to the socket. + /// + /// This is usually only done when establishing a server + /// socket. + /// + /// If reuseAddress is true, sets the SO_REUSEADDR + /// socket option. + /// + /// If reusePort is true, sets the SO_REUSEPORT + /// socket option. + virtual void bind6(const SocketAddress& address, bool reuseAddress = false, bool ipV6Only = false); /// Binds a local IPv6 address to the socket. /// @@ -106,6 +131,26 @@ public: /// If the library has not been built with IPv6 support, /// a Poco::NotImplementedException will be thrown. + virtual void bind6(const SocketAddress& address, bool reuseAddress, bool reusePort, bool ipV6Only); + /// Binds a local IPv6 address to the socket. + /// + /// This is usually only done when establishing a server + /// socket. TCP clients should not bind a socket to a + /// specific address. + /// + /// If reuseAddress is true, sets the SO_REUSEADDR + /// socket option. + /// + /// If reusePort is true, sets the SO_REUSEPORT + /// socket option. + /// + /// The given address must be an IPv6 address. The + /// IPPROTO_IPV6/IPV6_V6ONLY option is set on the socket + /// according to the ipV6Only parameter. + /// + /// If the library has not been built with IPv6 support, + /// a Poco::NotImplementedException will be thrown. + virtual void bind6(Poco::UInt16 port, bool reuseAddress = false, bool ipV6Only = false); /// Binds a local IPv6 port to the socket. /// @@ -122,6 +167,24 @@ public: /// If the library has not been built with IPv6 support, /// a Poco::NotImplementedException will be thrown. + virtual void bind6(Poco::UInt16 port, bool reuseAddress, bool reusePort, bool ipV6Only); + /// Binds a local IPv6 port to the socket. + /// + /// This is usually only done when establishing a server + /// socket. + /// + /// If reuseAddress is true, sets the SO_REUSEADDR + /// socket option. + /// + /// If reusePort is true, sets the SO_REUSEPORT + /// socket option. + /// The given address must be an IPv6 address. The + /// IPPROTO_IPV6/IPV6_V6ONLY option is set on the socket + /// according to the ipV6Only parameter. + /// + /// If the library has not been built with IPv6 support, + /// a Poco::NotImplementedException will be thrown. + virtual void listen(int backlog = 64); /// Puts the socket into listening state. /// diff --git a/Net/include/Poco/Net/SocketAddress.h b/Net/include/Poco/Net/SocketAddress.h index 8e3fb7733..1d5f03079 100644 --- a/Net/include/Poco/Net/SocketAddress.h +++ b/Net/include/Poco/Net/SocketAddress.h @@ -20,9 +20,14 @@ #include "Poco/Net/Net.h" #include "Poco/Net/SocketAddressImpl.h" +#include namespace Poco { + +class BinaryReader; +class BinaryWriter; + namespace Net { @@ -36,9 +41,25 @@ class Net_API SocketAddress /// host address and a port number. { public: + // The following declarations keep the Family type + // backwards compatible with the previously used + // enum declaration. + typedef AddressFamily::Family Family; + static const Family IPv4 = AddressFamily::IPv4; +#if defined(POCO_HAVE_IPv6) + static const Family IPv6 = AddressFamily::IPv6; +#endif +#if defined(POCO_OS_FAMILY_UNIX) + static const Family UNIX_LOCAL = AddressFamily::UNIX_LOCAL; +#endif + SocketAddress(); /// Creates a wildcard (all zero) IPv4 SocketAddress. + explicit SocketAddress(Family family); + /// Creates a SocketAddress with unspecified (wildcard) IP address + /// of the given family. + SocketAddress(const IPAddress& hostAddress, Poco::UInt16 portNumber); /// Creates a SocketAddress from an IP address and given port number. @@ -46,12 +67,27 @@ public: /// Creates a SocketAddress with unspecified (wildcard) IP address /// and given port number. + SocketAddress(Family family, Poco::UInt16 port); + /// Creates a SocketAddress with unspecified (wildcard) IP address + /// of the given family, and given port number. + SocketAddress(const std::string& hostAddress, Poco::UInt16 portNumber); /// Creates a SocketAddress from an IP address and given port number. /// /// The IP address must either be a domain name, or it must /// be in dotted decimal (IPv4) or hex string (IPv6) format. + SocketAddress(Family family, const std::string& hostAddress, Poco::UInt16 portNumber); + /// Creates a SocketAddress from an IP address and given port number. + /// + /// The IP address must either be a domain name, or it must + /// be in dotted decimal (IPv4) or hex string (IPv6) format. + /// + /// If a domain name is given in hostAddress, it is resolved and the address + /// matching the given family is used. If no address matching the given family + /// is found, or the IP address given in hostAddress does not match the given + /// family, an AddressFamilyMismatchException is thrown. + SocketAddress(const std::string& hostAddress, const std::string& portNumber); /// Creates a SocketAddress from an IP address and the /// service name or port number. @@ -62,6 +98,21 @@ public: /// The given port must either be a decimal port number, or /// a service name. + SocketAddress(Family family, const std::string& hostAddress, const std::string& portNumber); + /// Creates a SocketAddress from an IP address and the + /// service name or port number. + /// + /// The IP address must either be a domain name, or it must + /// be in dotted decimal (IPv4) or hex string (IPv6) format. + /// + /// The given port must either be a decimal port number, or + /// a service name. + /// + /// If a domain name is given in hostAddress, it is resolved and the address + /// matching the given family is used. If no address matching the given family + /// is found, or the IP address given in hostAddress does not match the given + /// family, an AddressFamilyMismatchException is thrown. + explicit SocketAddress(const std::string& hostAndPort); /// Creates a SocketAddress from an IP address or host name and the /// port number/service name. Host name/address and port number must @@ -72,6 +123,17 @@ public: /// 192.168.1.10:80 /// [::ffff:192.168.1.120]:2040 /// www.appinf.com:8080 + /// + /// On POSIX platforms supporting UNIX_LOCAL sockets, hostAndPort + /// can also be the absolute path of a local socket, starting with a + /// slash, e.g. "/tmp/local.socket". + + SocketAddress(Family family, const std::string& addr); + /// Creates a SocketAddress of the given family from a + /// string representation of the address, which is + /// either an IP address and port number, separated by + /// a colon for IPv4 or IPv6 addresses, or a path for + /// UNIX_LOCAL sockets. SocketAddress(const SocketAddress& addr); /// Creates a SocketAddress by copying another one. @@ -103,7 +165,7 @@ public: std::string toString() const; /// Returns a string representation of the address. - IPAddress::Family family() const; + Family family() const; /// Returns the address family of the host's address. bool operator < (const SocketAddress& socketAddress) const; @@ -113,7 +175,9 @@ public: enum { MAX_ADDRESS_LENGTH = -#if defined(POCO_HAVE_IPv6) +#if defined(POCO_OS_FAMILY_UNIX) + sizeof(struct sockaddr_un) +#elif defined(POCO_HAVE_IPv6) sizeof(struct sockaddr_in6) #else sizeof(struct sockaddr_in) @@ -124,6 +188,9 @@ public: protected: void init(const IPAddress& hostAddress, Poco::UInt16 portNumber); void init(const std::string& hostAddress, Poco::UInt16 portNumber); + void init(Family family, const std::string& hostAddress, Poco::UInt16 portNumber); + void init(Family family, const std::string& address); + void init(const std::string& hostAndPort); Poco::UInt16 resolveService(const std::string& service); private: @@ -137,14 +204,18 @@ private: Ptr pImpl() const; void newIPv4(); - void newIPv4(const sockaddr_in*); - void newIPv4(const IPAddress& hostAddress, Poco::UInt16 portNumber); +#if defined(POCO_HAVE_IPv6) void newIPv6(const sockaddr_in6*); - void newIPv6(const IPAddress& hostAddress, Poco::UInt16 portNumber); +#endif + +#if defined(POCO_OS_FAMILY_UNIX) + void newLocal(const sockaddr_un* sockAddr); + void newLocal(const std::string& path); +#endif void destruct(); @@ -161,7 +232,11 @@ private: AlignerType aligner; } #else // !POCO_ENABLE_CPP11 - AlignedCharArrayUnion + #if defined(POCO_HAVE_IPv6) + AlignedCharArrayUnion + #else + AlignedCharArrayUnion + #endif #endif // POCO_ENABLE_CPP11 _memory; #else // !POCO_HAVE_ALIGNMENT @@ -224,7 +299,7 @@ inline void SocketAddress::newIPv4(const IPAddress& hostAddress, Poco::UInt16 po } - +#if defined(POCO_HAVE_IPv6) inline void SocketAddress::newIPv6(const sockaddr_in6* sockAddr) { #ifdef POCO_HAVE_ALIGNMENT @@ -243,14 +318,31 @@ inline void SocketAddress::newIPv6(const IPAddress& hostAddress, Poco::UInt16 po _pImpl = new Poco::Net::Impl::IPv6SocketAddressImpl(hostAddress.addr(), htons(portNumber), hostAddress.scope()); #endif } +#endif // POCO_HAVE_IPv6 -inline IPAddress::Family SocketAddress::family() const +#if defined(POCO_OS_FAMILY_UNIX) +inline void SocketAddress::newLocal(const sockaddr_un* sockAddr) { - return host().family(); +#ifdef POCO_HAVE_ALIGNMENT + new (storage()) Poco::Net::Impl::LocalSocketAddressImpl(sockAddr); +#else + _pImpl = new Poco::Net::Impl::LocalSocketAddressImpl(sockAddr); +#endif } +inline void SocketAddress::newLocal(const std::string& path) +{ +#ifdef POCO_HAVE_ALIGNMENT + new (storage()) Poco::Net::Impl::LocalSocketAddressImpl(path.c_str()); +#else + _pImpl = new Poco::Net::Impl::LocalSocketAddressImpl(path.c_str()); +#endif +} +#endif // POCO_OS_FAMILY_UNIX + + #ifdef POCO_HAVE_ALIGNMENT inline char* SocketAddress::storage() { @@ -259,19 +351,29 @@ inline char* SocketAddress::storage() #endif -inline bool SocketAddress::operator == (const SocketAddress& socketAddress) const +inline bool SocketAddress::operator == (const SocketAddress& socketAddress) const { - return host() == socketAddress.host() && port() == socketAddress.port(); +#if defined(POCO_OS_FAMILY_UNIX) + if (family() == UNIX_LOCAL) + return toString() == socketAddress.toString(); + else +#endif + return host() == socketAddress.host() && port() == socketAddress.port(); } inline bool SocketAddress::operator != (const SocketAddress& socketAddress) const { - return host() != socketAddress.host() || port() != socketAddress.port(); + return !(operator == (socketAddress)); } } } // namespace Poco::Net +Net_API Poco::BinaryWriter& operator << (Poco::BinaryWriter& writer, const Poco::Net::SocketAddress& value); +Net_API Poco::BinaryReader& operator >> (Poco::BinaryReader& reader, Poco::Net::SocketAddress& value); +Net_API std::ostream& operator << (std::ostream& ostr, const Poco::Net::SocketAddress& address); + + #endif // Net_SocketAddress_INCLUDED diff --git a/Net/include/Poco/Net/SocketAddressImpl.h b/Net/include/Poco/Net/SocketAddressImpl.h index d5805e2bd..689a10fc3 100644 --- a/Net/include/Poco/Net/SocketAddressImpl.h +++ b/Net/include/Poco/Net/SocketAddressImpl.h @@ -37,6 +37,8 @@ class Net_API SocketAddressImpl #endif { public: + typedef AddressFamily::Family Family; + virtual ~SocketAddressImpl(); virtual IPAddress host() const = 0; @@ -44,6 +46,8 @@ public: virtual poco_socklen_t length() const = 0; virtual const struct sockaddr* addr() const = 0; virtual int af() const = 0; + virtual Family family() const = 0; + virtual std::string toString() const = 0; protected: SocketAddressImpl(); @@ -65,7 +69,7 @@ public: poco_socklen_t length() const; const struct sockaddr* addr() const; int af() const; - IPAddress::Family family() const; + Family family() const; std::string toString() const; private: @@ -107,6 +111,12 @@ inline int IPv4SocketAddressImpl::af() const } +inline SocketAddressImpl::Family IPv4SocketAddressImpl::family() const +{ + return AddressFamily::IPv4; +} + + #if defined(POCO_HAVE_IPv6) @@ -121,6 +131,8 @@ public: poco_socklen_t length() const; const struct sockaddr* addr() const; int af() const; + Family family() const; + std::string toString() const; private: struct sockaddr_in6 _addr; @@ -161,7 +173,87 @@ inline int IPv6SocketAddressImpl::af() const } -#endif //POCO_HAVE_IPv6 +inline SocketAddressImpl::Family IPv6SocketAddressImpl::family() const +{ + return AddressFamily::IPv6; +} + + +#endif // POCO_HAVE_IPv6 + + +#if defined(POCO_OS_FAMILY_UNIX) + + +class Net_API LocalSocketAddressImpl: public SocketAddressImpl +{ +public: + LocalSocketAddressImpl(const struct sockaddr_un* addr); + LocalSocketAddressImpl(const char* path); + ~LocalSocketAddressImpl(); + IPAddress host() const; + UInt16 port() const; + poco_socklen_t length() const; + const struct sockaddr* addr() const; + int af() const; + Family family() const; + const char* path() const; + std::string toString() const; + +private: + struct sockaddr_un* _pAddr; + // Note: We allocate struct sockaddr_un on the heap, otherwise we would + // waste a lot of memory due to small object optimization in SocketAddress. +}; + + +// +// inlines +// + +inline IPAddress LocalSocketAddressImpl::host() const +{ + throw Poco::InvalidAccessException("local socket address does not have host IP address"); +} + + +inline UInt16 LocalSocketAddressImpl::port() const +{ + throw Poco::InvalidAccessException("local socket address does not have port number"); +} + + +inline poco_socklen_t LocalSocketAddressImpl::length() const +{ + return sizeof(struct sockaddr_un); +} + + +inline const struct sockaddr* LocalSocketAddressImpl::addr() const +{ + return reinterpret_cast(_pAddr); +} + + +inline int LocalSocketAddressImpl::af() const +{ + return _pAddr->sun_family; +} + + +inline SocketAddressImpl::Family LocalSocketAddressImpl::family() const +{ + return AddressFamily::UNIX_LOCAL; +} + + +inline const char* LocalSocketAddressImpl::path() const +{ + return _pAddr->sun_path; +} + + +#endif // POCO_OS_FAMILY_UNIX } } } // namespace Poco::Net::Impl diff --git a/Net/include/Poco/Net/SocketDefs.h b/Net/include/Poco/Net/SocketDefs.h index f692d46b0..590635ac4 100644 --- a/Net/include/Poco/Net/SocketDefs.h +++ b/Net/include/Poco/Net/SocketDefs.h @@ -132,6 +132,7 @@ #include #include #include + #include #include #if POCO_OS != POCO_OS_HPUX #include @@ -269,15 +270,19 @@ #if defined(POCO_HAVE_SALEN) - #define poco_set_sa_len(pSA, len) (pSA)->sa_len = (len) - #define poco_set_sin_len(pSA) (pSA)->sin_len = sizeof(struct sockaddr_in) + #define poco_set_sa_len(pSA, len) (pSA)->sa_len = (len) + #define poco_set_sin_len(pSA) (pSA)->sin_len = sizeof(struct sockaddr_in) #if defined(POCO_HAVE_IPv6) #define poco_set_sin6_len(pSA) (pSA)->sin6_len = sizeof(struct sockaddr_in6) #endif + #if defined(POCO_OS_FAMILY_UNIX) + #define poco_set_sun_len(pSA, len) (pSA)->sun_len = (len) + #endif #else - #define poco_set_sa_len(pSA, len) (void) 0 - #define poco_set_sin_len(pSA) (void) 0 - #define poco_set_sin6_len(pSA) (void) 0 + #define poco_set_sa_len(pSA, len) (void) 0 + #define poco_set_sin_len(pSA) (void) 0 + #define poco_set_sin6_len(pSA) (void) 0 + #define poco_set_sun_len(pSA, len) (void) 0 #endif @@ -346,4 +351,32 @@ #endif +namespace Poco { +namespace Net { + + +struct AddressFamily + /// AddressFamily::Family replaces the previously used IPAddress::Family + /// enumeration and is now used for IPAddress::Family and SocketAddress::Family. +{ + enum Family + /// Possible address families for socket addresses. + { + IPv4, + /// IPv4 address family. + #if defined(POCO_HAVE_IPv6) + IPv6, + /// IPv6 address family. + #endif + #if defined(POCO_OS_FAMILY_UNIX) + UNIX_LOCAL + /// UNIX domain socket address family. Available on UNIX/POSIX platforms only. + #endif + }; +}; + + +} } // namespace Poco::Net + + #endif // Net_SocketDefs_INCLUDED diff --git a/Net/include/Poco/Net/SocketImpl.h b/Net/include/Poco/Net/SocketImpl.h index 8bad99e18..423cb8dab 100644 --- a/Net/include/Poco/Net/SocketImpl.h +++ b/Net/include/Poco/Net/SocketImpl.h @@ -84,6 +84,19 @@ public: /// If reuseAddress is true, sets the SO_REUSEADDR /// socket option. + virtual void bind(const SocketAddress& address, bool reuseAddress, bool reusePort ); + /// Bind a local address to the socket. + /// + /// This is usually only done when establishing a server + /// socket. TCP clients should not bind a socket to a + /// specific address. + /// + /// If reuseAddress is true, sets the SO_REUSEADDR + /// socket option. + /// + /// If reusePort is true, sets the SO_REUSEPORT + /// socket option. + virtual void bind6(const SocketAddress& address, bool reuseAddress = false, bool ipV6Only = false); /// Bind a local IPv6 address to the socket. /// @@ -101,6 +114,26 @@ public: /// If the library has not been built with IPv6 support, /// a Poco::NotImplementedException will be thrown. + virtual void bind6(const SocketAddress& address, bool reuseAddress, bool reusePort, bool ipV6Only); + /// Bind a local IPv6 address to the socket. + /// + /// This is usually only done when establishing a server + /// socket. TCP clients should not bind a socket to a + /// specific address. + /// + /// If reuseAddress is true, sets the SO_REUSEADDR + /// socket option. + /// + /// If reusePort is true, sets the SO_REUSEPORT + /// socket option. + /// + /// The given address must be an IPv6 address. The + /// IPPROTO_IPV6/IPV6_V6ONLY option is set on the socket + /// according to the ipV6Only parameter. + /// + /// If the library has not been built with IPv6 support, + /// a Poco::NotImplementedException will be thrown. + virtual void listen(int backlog = 64); /// Puts the socket into listening state. /// @@ -419,11 +452,10 @@ private: SocketImpl& operator = (const SocketImpl&); poco_socket_t _sockfd; -#if defined(POCO_BROKEN_TIMEOUTS) Poco::Timespan _recvTimeout; Poco::Timespan _sndTimeout; -#endif bool _blocking; + bool _isBrokenTimeout; friend class Socket; friend class SecureSocketImpl; diff --git a/Net/include/Poco/Net/StreamSocket.h b/Net/include/Poco/Net/StreamSocket.h index f2a13f2e3..46374d85d 100644 --- a/Net/include/Poco/Net/StreamSocket.h +++ b/Net/include/Poco/Net/StreamSocket.h @@ -45,7 +45,7 @@ public: /// Creates a stream socket and connects it to /// the socket specified by address. - explicit StreamSocket(IPAddress::Family family); + explicit StreamSocket(SocketAddress::Family family); /// Creates an unconnected stream socket /// for the given address family. /// @@ -158,7 +158,7 @@ public: StreamSocket(SocketImpl* pImpl); /// Creates the Socket and attaches the given SocketImpl. - /// The socket takes owership of the SocketImpl. + /// The socket takes ownership of the SocketImpl. /// /// The SocketImpl must be a StreamSocketImpl, otherwise /// an InvalidArgumentException will be thrown. diff --git a/Net/include/Poco/Net/StreamSocketImpl.h b/Net/include/Poco/Net/StreamSocketImpl.h index fb7979cdf..eb4196983 100644 --- a/Net/include/Poco/Net/StreamSocketImpl.h +++ b/Net/include/Poco/Net/StreamSocketImpl.h @@ -33,7 +33,7 @@ public: StreamSocketImpl(); /// Creates a StreamSocketImpl. - explicit StreamSocketImpl(IPAddress::Family addressFamily); + explicit StreamSocketImpl(SocketAddress::Family addressFamily); /// Creates a SocketImpl, with the underlying /// socket initialized for the given address family. diff --git a/Net/include/Poco/Net/TCPServer.h b/Net/include/Poco/Net/TCPServer.h index 6845276c5..973bdde2e 100644 --- a/Net/include/Poco/Net/TCPServer.h +++ b/Net/include/Poco/Net/TCPServer.h @@ -22,6 +22,8 @@ #include "Poco/Net/ServerSocket.h" #include "Poco/Net/TCPServerConnectionFactory.h" #include "Poco/Net/TCPServerParams.h" +#include "Poco/RefCountedObject.h" +#include "Poco/AutoPtr.h" #include "Poco/Runnable.h" #include "Poco/Thread.h" #include "Poco/ThreadPool.h" @@ -32,6 +34,35 @@ namespace Net { class TCPServerDispatcher; +class StreamSocket; + + +class Net_API TCPServerConnectionFilter: public Poco::RefCountedObject + /// A TCPServerConnectionFilter can be used to reject incoming connections + /// before passing them on to the TCPServerDispatcher and + /// starting a thread to handle them. + /// + /// An example use case is white-list or black-list IP address filtering. + /// + /// Subclasses must override the accept() method. +{ +public: + typedef Poco::AutoPtr Ptr; + + virtual bool accept(const StreamSocket& socket) = 0; + /// Returns true if the given StreamSocket connection should + /// be handled, and passed on to the TCPServerDispatcher. + /// + /// Returns false if the socket should be closed immediately. + /// + /// The socket can be prevented from being closed immediately + /// if false is returned by creating a copy of the socket. + /// This can be used to handle certain socket connections in + /// a special way, outside the TCPServer framework. + +protected: + virtual ~TCPServerConnectionFilter(); +}; class Net_API TCPServer: public Poco::Runnable @@ -164,6 +195,19 @@ public: Poco::UInt16 port() const; /// Returns the port the server socket listens on. + void setConnectionFilter(const TCPServerConnectionFilter::Ptr& pFilter); + /// Sets a TCPServerConnectionFilter. Can also be used to remove + /// a filter by passing a null pointer. + /// + /// To avoid a potential race condition, the filter must + /// be set before the TCPServer is started. Trying to set + /// the filter after start() has been called will trigger + /// an assertion. + + TCPServerConnectionFilter::Ptr getConnectionFilter() const; + /// Returns the TCPServerConnectionFilter set with setConnectionFilter(), + /// or null pointer if no filter has been set. + protected: void run(); /// Runs the server. The server will run until @@ -179,10 +223,11 @@ private: TCPServer(const TCPServer&); TCPServer& operator = (const TCPServer&); - ServerSocket _socket; + ServerSocket _socket; TCPServerDispatcher* _pDispatcher; - Poco::Thread _thread; - bool _stopped; + TCPServerConnectionFilter::Ptr _pConnectionFilter; + Poco::Thread _thread; + bool _stopped; }; @@ -201,6 +246,12 @@ inline Poco::UInt16 TCPServer::port() const } +inline TCPServerConnectionFilter::Ptr TCPServer::getConnectionFilter() const +{ + return _pConnectionFilter; +} + + } } // namespace Poco::Net diff --git a/Net/include/Poco/Net/WebSocket.h b/Net/include/Poco/Net/WebSocket.h index daa44d2aa..34e08dd21 100644 --- a/Net/include/Poco/Net/WebSocket.h +++ b/Net/include/Poco/Net/WebSocket.h @@ -21,6 +21,7 @@ #include "Poco/Net/Net.h" #include "Poco/Net/StreamSocket.h" #include "Poco/Net/HTTPCredentials.h" +#include "Poco/Buffer.h" namespace Poco { @@ -219,6 +220,21 @@ public: /// The frame flags and opcode (FrameFlags and FrameOpcodes) /// is stored in flags. + int receiveFrame(Poco::Buffer& buffer, int& flags); + /// Receives a frame from the socket and stores it + /// after any previous content in buffer. + /// + /// Returns the number of bytes received. + /// A return value of 0 means that the peer has + /// shut down or closed the connection. + /// + /// Throws a TimeoutException if a receive timeout has + /// been set and nothing is received within that interval. + /// Throws a NetException (or a subclass) in case of other errors. + /// + /// The frame flags and opcode (FrameFlags and FrameOpcodes) + /// is stored in flags. + Mode mode() const; /// Returns WS_SERVER if the WebSocket is a server-side /// WebSocket, or WS_CLIENT otherwise. diff --git a/Net/include/Poco/Net/WebSocketImpl.h b/Net/include/Poco/Net/WebSocketImpl.h index 7640b7d43..584b3930e 100644 --- a/Net/include/Poco/Net/WebSocketImpl.h +++ b/Net/include/Poco/Net/WebSocketImpl.h @@ -19,6 +19,7 @@ #include "Poco/Net/StreamSocketImpl.h" +#include "Poco/Buffer.h" #include "Poco/Random.h" #include "Poco/Buffer.h" @@ -45,12 +46,17 @@ public: virtual int receiveBytes(void* buffer, int length, int flags); /// Receives a WebSocket protocol frame. + virtual int receiveBytes(Poco::Buffer& buffer, int flags); + /// Receives a WebSocket protocol frame. + virtual SocketImpl* acceptConnection(SocketAddress& clientAddr); virtual void connect(const SocketAddress& address); virtual void connect(const SocketAddress& address, const Poco::Timespan& timeout); virtual void connectNB(const SocketAddress& address); virtual void bind(const SocketAddress& address, bool reuseAddress = false); + virtual void bind(const SocketAddress& address, bool reuseAddress, bool reusePort); virtual void bind6(const SocketAddress& address, bool reuseAddress = false, bool ipV6Only = false); + virtual void bind6(const SocketAddress& address, bool reuseAddress, bool reusePort, bool ipV6Only); virtual void listen(int backlog = 64); virtual void close(); virtual void shutdownReceive(); @@ -80,6 +86,8 @@ protected: MAX_HEADER_LENGTH = 14 }; + int receiveHeader(char mask[4], bool& useMask); + int receivePayload(char *buffer, int payloadLength, char mask[4], bool useMask); int receiveNBytes(void* buffer, int bytes); int receiveSomeBytes(char* buffer, int bytes); virtual ~WebSocketImpl(); diff --git a/Net/src/DatagramSocket.cpp b/Net/src/DatagramSocket.cpp index eb45c5686..8d7cc92e3 100644 --- a/Net/src/DatagramSocket.cpp +++ b/Net/src/DatagramSocket.cpp @@ -29,7 +29,7 @@ DatagramSocket::DatagramSocket(): Socket(new DatagramSocketImpl) } -DatagramSocket::DatagramSocket(IPAddress::Family family): Socket(new DatagramSocketImpl(family)) +DatagramSocket::DatagramSocket(SocketAddress::Family family): Socket(new DatagramSocketImpl(family)) { } @@ -81,6 +81,12 @@ void DatagramSocket::bind(const SocketAddress& address, bool 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); diff --git a/Net/src/DatagramSocketImpl.cpp b/Net/src/DatagramSocketImpl.cpp index 62c6ad203..9b86ebe61 100644 --- a/Net/src/DatagramSocketImpl.cpp +++ b/Net/src/DatagramSocketImpl.cpp @@ -25,17 +25,20 @@ namespace Net { DatagramSocketImpl::DatagramSocketImpl() { - init(AF_INET); } -DatagramSocketImpl::DatagramSocketImpl(IPAddress::Family family) +DatagramSocketImpl::DatagramSocketImpl(SocketAddress::Family family) { - if (family == IPAddress::IPv4) + if (family == SocketAddress::IPv4) init(AF_INET); #if defined(POCO_HAVE_IPv6) - else if (family == IPAddress::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"); } diff --git a/Net/src/HTTPClientSession.cpp b/Net/src/HTTPClientSession.cpp index 45f09594b..336a6b617 100644 --- a/Net/src/HTTPClientSession.cpp +++ b/Net/src/HTTPClientSession.cpp @@ -44,7 +44,8 @@ HTTPClientSession::HTTPClientSession(): _keepAliveTimeout(DEFAULT_KEEP_ALIVE_TIMEOUT, 0), _reconnect(false), _mustReconnect(false), - _expectResponseBody(false) + _expectResponseBody(false), + _responseReceived(false) { } @@ -56,7 +57,8 @@ HTTPClientSession::HTTPClientSession(const StreamSocket& socket): _keepAliveTimeout(DEFAULT_KEEP_ALIVE_TIMEOUT, 0), _reconnect(false), _mustReconnect(false), - _expectResponseBody(false) + _expectResponseBody(false), + _responseReceived(false) { } @@ -68,7 +70,8 @@ HTTPClientSession::HTTPClientSession(const SocketAddress& address): _keepAliveTimeout(DEFAULT_KEEP_ALIVE_TIMEOUT, 0), _reconnect(false), _mustReconnect(false), - _expectResponseBody(false) + _expectResponseBody(false), + _responseReceived(false) { } @@ -80,7 +83,8 @@ HTTPClientSession::HTTPClientSession(const std::string& host, Poco::UInt16 port) _keepAliveTimeout(DEFAULT_KEEP_ALIVE_TIMEOUT, 0), _reconnect(false), _mustReconnect(false), - _expectResponseBody(false) + _expectResponseBody(false), + _responseReceived(false) { } @@ -92,7 +96,8 @@ HTTPClientSession::HTTPClientSession(const std::string& host, Poco::UInt16 port, _keepAliveTimeout(DEFAULT_KEEP_ALIVE_TIMEOUT, 0), _reconnect(false), _mustReconnect(false), - _expectResponseBody(false) + _expectResponseBody(false), + _responseReceived(false) { } @@ -190,9 +195,10 @@ std::ostream& HTTPClientSession::sendRequest(HTTPRequest& request) { clearException(); _pResponseStream = 0; + _responseReceived = false; bool keepAlive = getKeepAlive(); - if ((connected() && !keepAlive) || mustReconnect()) + if (((connected() && !keepAlive) || mustReconnect()) && !_host.empty()) { close(); _mustReconnect = false; @@ -203,7 +209,7 @@ std::ostream& HTTPClientSession::sendRequest(HTTPRequest& request) reconnect(); if (!keepAlive) request.setKeepAlive(false); - if (!request.has(HTTPRequest::HOST)) + if (!request.has(HTTPRequest::HOST) && !_host.empty()) request.setHost(_host, _port); if (!_proxyConfig.host.empty() && !bypassProxy()) { @@ -258,25 +264,28 @@ std::istream& HTTPClientSession::receiveResponse(HTTPResponse& response) _pRequestStream = 0; if (networkException()) networkException()->rethrow(); - do + if (!_responseReceived) { - response.clear(); - HTTPHeaderInputStream his(*this); - try + do { - response.read(his); - } - catch (Exception&) - { - close(); - if (networkException()) - networkException()->rethrow(); - else + response.clear(); + HTTPHeaderInputStream his(*this); + try + { + response.read(his); + } + catch (Exception&) + { + close(); + if (networkException()) + networkException()->rethrow(); + else + throw; throw; - throw; + } } + while (response.getStatus() == HTTPResponse::HTTP_CONTINUE); } - while (response.getStatus() == HTTPResponse::HTTP_CONTINUE); _mustReconnect = getKeepAlive() && !response.getKeepAlive(); @@ -297,6 +306,34 @@ std::istream& HTTPClientSession::receiveResponse(HTTPResponse& response) } +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(); diff --git a/Net/src/HTTPRequest.cpp b/Net/src/HTTPRequest.cpp index 0c6f82b4f..52b3cf2f7 100644 --- a/Net/src/HTTPRequest.cpp +++ b/Net/src/HTTPRequest.cpp @@ -41,6 +41,7 @@ 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(): @@ -257,4 +258,20 @@ void HTTPRequest::setCredentials(const std::string& header, const std::string& s } +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 diff --git a/Net/src/HTTPResponse.cpp b/Net/src/HTTPResponse.cpp index 4bd14ba68..b9deb991e 100644 --- a/Net/src/HTTPResponse.cpp +++ b/Net/src/HTTPResponse.cpp @@ -38,6 +38,7 @@ 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"; @@ -45,13 +46,17 @@ const std::string HTTPResponse::HTTP_REASON_NONAUTHORITATIVE = "N 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_USEPROXY = "Use Proxy"; +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"; @@ -65,17 +70,33 @@ const std::string HTTPResponse::HTTP_REASON_CONFLICT = "C 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_REQUESTENTITYTOOLARGE = "Request Entity Too Large"; -const std::string HTTPResponse::HTTP_REASON_REQUESTURITOOLONG = "Request-URI Too Large"; -const std::string HTTPResponse::HTTP_REASON_UNSUPPORTEDMEDIATYPE = "Unsupported Media Type"; +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_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"; @@ -238,6 +259,8 @@ const std::string& HTTPResponse::getReasonForStatus(HTTPStatus status) 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: @@ -252,6 +275,12 @@ const std::string& HTTPResponse::getReasonForStatus(HTTPStatus status) 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: @@ -262,8 +291,8 @@ const std::string& HTTPResponse::getReasonForStatus(HTTPStatus status) return HTTP_REASON_SEE_OTHER; case HTTP_NOT_MODIFIED: return HTTP_REASON_NOT_MODIFIED; - case HTTP_USEPROXY: - return HTTP_REASON_USEPROXY; + case HTTP_USE_PROXY: + return HTTP_REASON_USE_PROXY; case HTTP_TEMPORARY_REDIRECT: return HTTP_REASON_TEMPORARY_REDIRECT; case HTTP_BAD_REQUEST: @@ -292,16 +321,38 @@ const std::string& HTTPResponse::getReasonForStatus(HTTPStatus status) return HTTP_REASON_LENGTH_REQUIRED; case HTTP_PRECONDITION_FAILED: return HTTP_REASON_PRECONDITION_FAILED; - case HTTP_REQUESTENTITYTOOLARGE: - return HTTP_REASON_REQUESTENTITYTOOLARGE; - case HTTP_REQUESTURITOOLONG: - return HTTP_REASON_REQUESTURITOOLONG; - case HTTP_UNSUPPORTEDMEDIATYPE: - return HTTP_REASON_UNSUPPORTEDMEDIATYPE; + 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: @@ -314,6 +365,16 @@ const std::string& HTTPResponse::getReasonForStatus(HTTPStatus status) 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; } diff --git a/Net/src/HTTPServerConnection.cpp b/Net/src/HTTPServerConnection.cpp index abcf4fb93..a6c27ce8c 100644 --- a/Net/src/HTTPServerConnection.cpp +++ b/Net/src/HTTPServerConnection.cpp @@ -83,7 +83,7 @@ void HTTPServerConnection::run() #endif if (pHandler.get()) { - if (request.expectContinue()) + if (request.getExpectContinue() && response.getStatus() == HTTPResponse::HTTP_OK) response.sendContinue(); pHandler->handleRequest(request, response); diff --git a/Net/src/HTTPServerRequestImpl.cpp b/Net/src/HTTPServerRequestImpl.cpp index 86d524043..d8ea7398c 100644 --- a/Net/src/HTTPServerRequestImpl.cpp +++ b/Net/src/HTTPServerRequestImpl.cpp @@ -20,6 +20,7 @@ #include "Poco/Net/HTTPFixedLengthStream.h" #include "Poco/Net/HTTPChunkedStream.h" #include "Poco/Net/HTTPServerParams.h" +#include "Poco/Net/StreamSocket.h" #include "Poco/String.h" @@ -30,9 +31,6 @@ namespace Poco { namespace Net { -const std::string HTTPServerRequestImpl::EXPECT("Expect"); - - HTTPServerRequestImpl::HTTPServerRequestImpl(HTTPServerResponseImpl& response, HTTPServerSession& session, HTTPServerParams* pParams): _response(response), _session(session), @@ -69,6 +67,12 @@ HTTPServerRequestImpl::~HTTPServerRequestImpl() } +bool HTTPServerRequestImpl::secure() const +{ + return _session.socket().secure(); +} + + StreamSocket& HTTPServerRequestImpl::socket() { return _session.socket(); @@ -81,11 +85,4 @@ StreamSocket HTTPServerRequestImpl::detachSocket() } -bool HTTPServerRequestImpl::expectContinue() const -{ - const std::string& expect = get(EXPECT, EMPTY); - return !expect.empty() && icompare(expect, "100-continue") == 0; -} - - } } // namespace Poco::Net diff --git a/Net/src/HTTPSession.cpp b/Net/src/HTTPSession.cpp index 529dab8ca..cb6fdc25e 100644 --- a/Net/src/HTTPSession.cpp +++ b/Net/src/HTTPSession.cpp @@ -30,7 +30,9 @@ HTTPSession::HTTPSession(): _pCurrent(0), _pEnd(0), _keepAlive(false), - _timeout(HTTP_DEFAULT_TIMEOUT), + _connectionTimeout(HTTP_DEFAULT_CONNECTION_TIMEOUT), + _receiveTimeout(HTTP_DEFAULT_TIMEOUT), + _sendTimeout(HTTP_DEFAULT_TIMEOUT), _pException(0) { } @@ -42,7 +44,9 @@ HTTPSession::HTTPSession(const StreamSocket& socket): _pCurrent(0), _pEnd(0), _keepAlive(false), - _timeout(HTTP_DEFAULT_TIMEOUT), + _connectionTimeout(HTTP_DEFAULT_CONNECTION_TIMEOUT), + _receiveTimeout(HTTP_DEFAULT_TIMEOUT), + _sendTimeout(HTTP_DEFAULT_TIMEOUT), _pException(0) { } @@ -54,7 +58,9 @@ HTTPSession::HTTPSession(const StreamSocket& socket, bool keepAlive): _pCurrent(0), _pEnd(0), _keepAlive(keepAlive), - _timeout(HTTP_DEFAULT_TIMEOUT), + _connectionTimeout(HTTP_DEFAULT_CONNECTION_TIMEOUT), + _receiveTimeout(HTTP_DEFAULT_TIMEOUT), + _sendTimeout(HTTP_DEFAULT_TIMEOUT), _pException(0) { } @@ -89,7 +95,15 @@ void HTTPSession::setKeepAlive(bool keepAlive) void HTTPSession::setTimeout(const Poco::Timespan& timeout) { - _timeout = 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; } @@ -179,8 +193,9 @@ bool HTTPSession::connected() const void HTTPSession::connect(const SocketAddress& address) { - _socket.connect(address, _timeout); - _socket.setReceiveTimeout(_timeout); + _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. diff --git a/Net/src/HTTPStreamFactory.cpp b/Net/src/HTTPStreamFactory.cpp index d11ce5054..ee77d98ec 100644 --- a/Net/src/HTTPStreamFactory.cpp +++ b/Net/src/HTTPStreamFactory.cpp @@ -140,7 +140,7 @@ std::istream* HTTPStreamFactory::open(const URI& uri) { return new HTTPResponseStream(rs, pSession); } - else if (res.getStatus() == HTTPResponse::HTTP_USEPROXY && !retry) + 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 diff --git a/Net/src/ICMPClient.cpp b/Net/src/ICMPClient.cpp index 7cd0e6483..cfe92db01 100644 --- a/Net/src/ICMPClient.cpp +++ b/Net/src/ICMPClient.cpp @@ -34,7 +34,7 @@ namespace Poco { namespace Net { -ICMPClient::ICMPClient(IPAddress::Family family): +ICMPClient::ICMPClient(SocketAddress::Family family): _family(family) { } diff --git a/Net/src/IPAddress.cpp b/Net/src/IPAddress.cpp index d497419dd..d8b6d470f 100644 --- a/Net/src/IPAddress.cpp +++ b/Net/src/IPAddress.cpp @@ -33,13 +33,25 @@ 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(); @@ -50,8 +62,10 @@ IPAddress::IPAddress(const IPAddress& addr) { if (addr.family() == IPv4) newIPv4(addr.addr()); +#if defined(POCO_HAVE_IPv6) else newIPv6(addr.addr(), addr.scope()); +#endif } @@ -63,8 +77,7 @@ IPAddress::IPAddress(Family family) else if (family == IPv6) newIPv6(); #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()"); } @@ -219,8 +232,12 @@ IPAddress& IPAddress::operator = (const IPAddress& addr) destruct(); if (addr.family() == IPAddress::IPv4) newIPv4(addr.addr()); - else +#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; } @@ -228,7 +245,7 @@ IPAddress& IPAddress::operator = (const IPAddress& addr) IPAddress::Family IPAddress::family() const { - return static_cast(pImpl()->family()); + return pImpl()->family(); } @@ -561,19 +578,30 @@ IPAddress IPAddress::broadcast() } -BinaryWriter& operator << (BinaryWriter& writer, const IPAddress& value) +} } // namespace Poco::Net + + +Poco::BinaryWriter& operator << (Poco::BinaryWriter& writer, const Poco::Net::IPAddress& value) { - writer.stream().write((const char*) value.addr(), value.length()); + writer << static_cast(value.length()); + writer.writeRaw(reinterpret_cast(value.addr()), value.length()); return writer; } -BinaryReader& operator >> (BinaryReader& reader, IPAddress& value) + +Poco::BinaryReader& operator >> (Poco::BinaryReader& reader, Poco::Net::IPAddress& value) { char buf[sizeof(struct in6_addr)]; - reader.stream().read(buf, value.length()); - value = IPAddress(buf, value.length()); + Poco::UInt8 length; + reader >> length; + reader.readRaw(buf, length); + value = Poco::Net::IPAddress(buf, length); return reader; } -} } // namespace Poco::Net +std::ostream& operator << (std::ostream& ostr, const Poco::Net::IPAddress& addr) +{ + ostr << addr.toString(); + return ostr; +} diff --git a/Net/src/IPAddressImpl.cpp b/Net/src/IPAddressImpl.cpp index 8cacadce0..dcc63e686 100644 --- a/Net/src/IPAddressImpl.cpp +++ b/Net/src/IPAddressImpl.cpp @@ -143,7 +143,7 @@ const void* IPv4AddressImpl::addr() const IPAddressImpl::Family IPv4AddressImpl::family() const { - return IPAddressImpl::IPv4; + return AddressFamily::IPv4; } @@ -500,7 +500,7 @@ const void* IPv6AddressImpl::addr() const IPAddressImpl::Family IPv6AddressImpl::family() const { - return IPAddressImpl::IPv6; + return AddressFamily::IPv6; } @@ -535,6 +535,8 @@ unsigned IPv6AddressImpl::prefixLength() const throw NotImplementedException("prefixLength() not implemented"); #endif } + + Poco::UInt32 IPv6AddressImpl::scope() const { return _scope; diff --git a/Net/src/MessageHeader.cpp b/Net/src/MessageHeader.cpp index c5f0a5c53..f1537daf9 100644 --- a/Net/src/MessageHeader.cpp +++ b/Net/src/MessageHeader.cpp @@ -16,6 +16,11 @@ #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 namespace Poco { @@ -96,7 +101,7 @@ void MessageHeader::read(std::istream& istr) throw MessageException("Folded field value too long/no CRLF found"); } Poco::trimRightInPlace(value); - add(name, value); + add(name, decodeWord(value)); ++fields; } istr.putback(ch); @@ -252,4 +257,138 @@ void MessageHeader::quote(const std::string& value, std::string& result, bool al } +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 diff --git a/Net/src/MulticastSocket.cpp b/Net/src/MulticastSocket.cpp index 14eeca180..e302f6a81 100644 --- a/Net/src/MulticastSocket.cpp +++ b/Net/src/MulticastSocket.cpp @@ -51,8 +51,12 @@ MulticastSocket::MulticastSocket() } -MulticastSocket::MulticastSocket(IPAddress::Family family): DatagramSocket(family) +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 } @@ -80,18 +84,17 @@ MulticastSocket& MulticastSocket::operator = (const Socket& socket) void MulticastSocket::setInterface(const NetworkInterface& interfc) { - if (address().family() == IPAddress::IPv4) + 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() == IPAddress::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."); + else throw UnsupportedFamilyException("Unknown or unsupported socket family."); } diff --git a/Net/src/NetException.cpp b/Net/src/NetException.cpp index 26d3c1924..a167642b2 100644 --- a/Net/src/NetException.cpp +++ b/Net/src/NetException.cpp @@ -47,7 +47,8 @@ POCO_IMPLEMENT_EXCEPTION(ICMPException, NetException, "ICMP Exception") 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(UnsupportedFamilyException, NetException, "Unknown or unsupported socket family") +POCO_IMPLEMENT_EXCEPTION(AddressFamilyMismatchException, NetException, "Address family mismatch") } } // namespace Poco::Net diff --git a/Net/src/NetworkInterface.cpp b/Net/src/NetworkInterface.cpp index 45d6ca77b..49d6f5c8e 100644 --- a/Net/src/NetworkInterface.cpp +++ b/Net/src/NetworkInterface.cpp @@ -242,7 +242,7 @@ void NetworkInterfaceImpl::setPhyParams() #if !defined(POCO_OS_FAMILY_WINDOWS) && !defined(POCO_VXWORKS) struct ifreq ifr; std::strncpy(ifr.ifr_name, _name.c_str(), IFNAMSIZ); - DatagramSocket ds; + DatagramSocket ds(SocketAddress::IPv4); ds.impl()->ioctl(SIOCGIFFLAGS, &ifr); setFlags(ifr.ifr_flags); @@ -796,16 +796,10 @@ bool NetworkInterface::isUp() const NetworkInterface NetworkInterface::forName(const std::string& name, bool requireIPv6) { - Map map = NetworkInterface::map(false, false); - Map::const_iterator it = map.begin(); - Map::const_iterator end = map.end(); - - for (; it != end; ++it) - { - if (it->second.name() == name && ((requireIPv6 && it->second.supportsIPv6()) || !requireIPv6)) - return it->second; - } - throw InterfaceNotFoundException(name); + if (requireIPv6) + return forName(name, IPv6_ONLY); + else + return forName(name, IPv4_OR_IPv6); } diff --git a/Net/src/RawSocket.cpp b/Net/src/RawSocket.cpp index 6b907ed8c..7605dcac3 100644 --- a/Net/src/RawSocket.cpp +++ b/Net/src/RawSocket.cpp @@ -30,7 +30,7 @@ RawSocket::RawSocket(): } -RawSocket::RawSocket(IPAddress::Family family, int proto): +RawSocket::RawSocket(SocketAddress::Family family, int proto): Socket(new RawSocketImpl(family, proto)) { } @@ -84,6 +84,12 @@ void RawSocket::bind(const SocketAddress& address, bool 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); diff --git a/Net/src/RawSocketImpl.cpp b/Net/src/RawSocketImpl.cpp index a6da56747..c7fb248ef 100644 --- a/Net/src/RawSocketImpl.cpp +++ b/Net/src/RawSocketImpl.cpp @@ -29,12 +29,12 @@ RawSocketImpl::RawSocketImpl() } -RawSocketImpl::RawSocketImpl(IPAddress::Family family, int proto) +RawSocketImpl::RawSocketImpl(SocketAddress::Family family, int proto) { - if (family == IPAddress::IPv4) + if (family == SocketAddress::IPv4) init2(AF_INET, proto); #if defined(POCO_HAVE_IPv6) - else if (family == IPAddress::IPv6) + else if (family == SocketAddress::IPv6) init2(AF_INET6, proto); #endif else throw InvalidArgumentException("Invalid or unsupported address family passed to RawSocketImpl"); diff --git a/Net/src/ServerSocket.cpp b/Net/src/ServerSocket.cpp index 631761d3a..349cad3d4 100644 --- a/Net/src/ServerSocket.cpp +++ b/Net/src/ServerSocket.cpp @@ -78,6 +78,12 @@ void ServerSocket::bind(const SocketAddress& address, bool 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; @@ -86,17 +92,47 @@ void ServerSocket::bind(Poco::UInt16 port, bool 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 } diff --git a/Net/src/Socket.cpp b/Net/src/Socket.cpp index fae89d8ff..bd3a4ef03 100644 --- a/Net/src/Socket.cpp +++ b/Net/src/Socket.cpp @@ -22,9 +22,6 @@ #elif defined(POCO_HAVE_FD_POLL) #include "Poco/SharedPtr.h" #include -typedef Poco::SharedPtr > SharedPollArray; #endif @@ -209,6 +206,7 @@ int Socket::select(SocketList& readList, SocketList& writeList, SocketList& exce return readList.size() + writeList.size() + exceptList.size(); #elif defined(POCO_HAVE_FD_POLL) + typedef Poco::SharedPtr > SharedPollArray; nfds_t nfd = readList.size() + writeList.size() + exceptList.size(); if (0 == nfd) return 0; diff --git a/Net/src/SocketAddress.cpp b/Net/src/SocketAddress.cpp index 8d7becef4..21f6019ab 100644 --- a/Net/src/SocketAddress.cpp +++ b/Net/src/SocketAddress.cpp @@ -18,19 +18,24 @@ #include "Poco/Net/DNS.h" #include "Poco/RefCountedObject.h" #include "Poco/NumberParser.h" -#include "Poco/NumberFormatter.h" +#include "Poco/BinaryReader.h" +#include "Poco/BinaryWriter.h" #include #include using Poco::RefCountedObject; using Poco::NumberParser; -using Poco::NumberFormatter; 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 { @@ -51,12 +56,31 @@ struct AFLT // +#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); @@ -69,65 +93,76 @@ SocketAddress::SocketAddress(Poco::UInt16 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) { - 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 (*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)); + init(hostAndPort); } SocketAddress::SocketAddress(const SocketAddress& socketAddress) { - if (socketAddress.family() == IPAddress::IPv4) + if (socketAddress.family() == IPv4) newIPv4(reinterpret_cast(socketAddress.addr())); - else +#if defined(POCO_HAVE_IPv6) + else if (socketAddress.family() == IPv6) newIPv6(reinterpret_cast(socketAddress.addr())); +#endif +#if defined(POCO_OS_FAMILY_UNIX) + else if (socketAddress.family() == UNIX_LOCAL) + newLocal(reinterpret_cast(socketAddress.addr())); +#endif } SocketAddress::SocketAddress(const struct sockaddr* sockAddr, poco_socklen_t length) { - if (length == sizeof(struct sockaddr_in)) + if (length == sizeof(struct sockaddr_in) && sockAddr->sa_family == AF_INET) newIPv4(reinterpret_cast(sockAddr)); #if defined(POCO_HAVE_IPv6) - else if (length == sizeof(struct sockaddr_in6)) + else if (length == sizeof(struct sockaddr_in6) && sockAddr->sa_family == AF_INET6) newIPv6(reinterpret_cast(sockAddr)); #endif - else throw Poco::InvalidArgumentException("Invalid address length passed to SocketAddress()"); +#if defined(POCO_OS_FAMILY_UNIX) + else if (length > 0 && length <= sizeof(struct sockaddr_un) && sockAddr->sa_family == AF_UNIX) + newLocal(reinterpret_cast(sockAddr)); +#endif + else throw Poco::InvalidArgumentException("Invalid address length or family passed to SocketAddress()"); } @@ -141,6 +176,9 @@ 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()); @@ -152,10 +190,16 @@ SocketAddress& SocketAddress::operator = (const SocketAddress& socketAddress) if (&socketAddress != this) { destruct(); - if (socketAddress.family() == IPAddress::IPv4) + if (socketAddress.family() == IPv4) newIPv4(reinterpret_cast(socketAddress.addr())); - else +#if defined(POCO_HAVE_IPv6) + else if (socketAddress.family() == IPv6) newIPv6(reinterpret_cast(socketAddress.addr())); +#endif +#if defined(POCO_OS_FAMILY_UNIX) + else if (socketAddress.family() == UNIX_LOCAL) + newLocal(reinterpret_cast(socketAddress.addr())); +#endif } return *this; } @@ -191,19 +235,15 @@ int SocketAddress::af() const } +SocketAddress::Family SocketAddress::family() const +{ + return static_cast(pImpl()->family()); +} + + std::string SocketAddress::toString() const { - std::string result; -#if defined(POCO_HAVE_IPv6) - if (host().family() == IPAddress::IPv6) - result.append("["); - result.append(host().toString()); - if (host().family() == IPAddress::IPv6) - result.append("]"); -#endif - result.append(":"); - NumberFormatter::append(result, port()); - return result; + return pImpl()->toString(); } @@ -232,7 +272,7 @@ void SocketAddress::init(const std::string& hostAddress, Poco::UInt16 portNumber HostEntry::AddressList addresses = he.addresses(); if (addresses.size() > 0) { -#if defined(POCO_HAVE_IPv6) && !defined(POCO_SOCKETADDRESS_DONT_PREFER_IPV4) +#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 @@ -243,6 +283,109 @@ void SocketAddress::init(const std::string& hostAddress, Poco::UInt16 portNumber } +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 (HostEntry::AddressList::const_iterator it = addresses.begin(); it != addresses.end(); ++it) + { + if (it->family() == fam) + { + init(*it, 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; @@ -266,3 +409,29 @@ Poco::UInt16 SocketAddress::resolveService(const std::string& service) } } // 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; +} diff --git a/Net/src/SocketAddressImpl.cpp b/Net/src/SocketAddressImpl.cpp index 42dd8f8fe..a57114875 100644 --- a/Net/src/SocketAddressImpl.cpp +++ b/Net/src/SocketAddressImpl.cpp @@ -14,6 +14,7 @@ #include "Poco/Net/SocketAddressImpl.h" #include "Poco/Net/SocketDefs.h" +#include "Poco/NumberFormatter.h" #include @@ -60,11 +61,22 @@ 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) @@ -100,7 +112,59 @@ IPv6SocketAddressImpl::IPv6SocketAddressImpl(const void* addr, UInt16 port, UInt } +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) +{ + _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() +{ + delete _pAddr; +} + + +std::string LocalSocketAddressImpl::toString() const +{ + std::string result(path()); + return result; +} + + +#endif // POCO_OS_FAMILY_UNIX + + } } } // namespace Poco::Net::Impl diff --git a/Net/src/SocketImpl.cpp b/Net/src/SocketImpl.cpp index 251a46316..ce5d6e73c 100644 --- a/Net/src/SocketImpl.cpp +++ b/Net/src/SocketImpl.cpp @@ -31,6 +31,11 @@ #endif +#ifdef POCO_OS_FAMILY_WINDOWS +#include +#endif + + using Poco::IOException; using Poco::TimeoutException; using Poco::InvalidArgumentException; @@ -42,16 +47,34 @@ namespace Poco { namespace Net { +bool checkIsBrokenTimeout() +{ +#if defined(POCO_BROKEN_TIMEOUTS) + return true; +#elif defined(POCO_OS_FAMILY_WINDOWS) + // on Windows 7 and lower, socket timeouts have a minimum of 500ms, use poll for timeouts on this case + // https://social.msdn.microsoft.com/Forums/en-US/76620f6d-22b1-4872-aaf0-833204f3f867/minimum-timeout-value-for-sorcvtimeo + OSVERSIONINFO vi; + vi.dwOSVersionInfoSize = sizeof(vi); + if (GetVersionEx(&vi) == 0) return true; //throw SystemException("Cannot get OS version information"); + return vi.dwMajorVersion < 6 || (vi.dwMajorVersion == 6 && vi.dwMinorVersion < 2); +#endif + return false; +} + + SocketImpl::SocketImpl(): _sockfd(POCO_INVALID_SOCKET), - _blocking(true) + _blocking(true), + _isBrokenTimeout(checkIsBrokenTimeout()) { } SocketImpl::SocketImpl(poco_socket_t sockfd): _sockfd(sockfd), - _blocking(true) + _blocking(true), + _isBrokenTimeout(checkIsBrokenTimeout()) { } @@ -165,16 +188,21 @@ void SocketImpl::connectNB(const SocketAddress& address) void SocketImpl::bind(const SocketAddress& address, bool reuseAddress) +{ + bind(address, reuseAddress, true); +} + + +void SocketImpl::bind(const SocketAddress& address, bool reuseAddress, bool reusePort) { if (_sockfd == POCO_INVALID_SOCKET) { init(address.af()); } if (reuseAddress) - { setReuseAddress(true); + if (reusePort) setReusePort(true); - } #if defined(POCO_VXWORKS) int rc = ::bind(_sockfd, (sockaddr*) address.addr(), address.length()); #else @@ -185,9 +213,15 @@ void SocketImpl::bind(const SocketAddress& address, bool reuseAddress) void SocketImpl::bind6(const SocketAddress& address, bool reuseAddress, bool ipV6Only) +{ + bind6(address, reuseAddress, true, ipV6Only); +} + + +void SocketImpl::bind6(const SocketAddress& address, bool reuseAddress, bool reusePort, bool ipV6Only) { #if defined(POCO_HAVE_IPv6) - if (address.family() != IPAddress::IPv6) + if (address.family() != SocketAddress::IPv6) throw Poco::InvalidArgumentException("SocketAddress must be an IPv6 address"); if (_sockfd == POCO_INVALID_SOCKET) @@ -200,10 +234,9 @@ void SocketImpl::bind6(const SocketAddress& address, bool reuseAddress, bool ipV if (ipV6Only) throw Poco::NotImplementedException("IPV6_V6ONLY not defined."); #endif if (reuseAddress) - { setReuseAddress(true); + if (reusePort) setReusePort(true); - } int rc = ::bind(_sockfd, address.addr(), address.length()); if (rc != 0) error(address.toString()); #else @@ -260,13 +293,14 @@ void SocketImpl::shutdown() int SocketImpl::sendBytes(const void* buffer, int length, int flags) { -#if defined(POCO_BROKEN_TIMEOUTS) - if (_sndTimeout.totalMicroseconds() != 0) + if (_isBrokenTimeout) { - if (!poll(_sndTimeout, SELECT_WRITE)) - throw TimeoutException(); + if (_sndTimeout.totalMicroseconds() != 0) + { + if (!poll(_sndTimeout, SELECT_WRITE)) + throw TimeoutException(); + } } -#endif int rc; do @@ -282,13 +316,14 @@ int SocketImpl::sendBytes(const void* buffer, int length, int flags) int SocketImpl::receiveBytes(void* buffer, int length, int flags) { -#if defined(POCO_BROKEN_TIMEOUTS) - if (_recvTimeout.totalMicroseconds() != 0) + if (_isBrokenTimeout) { - if (!poll(_recvTimeout, SELECT_READ)) - throw TimeoutException(); + if (_recvTimeout.totalMicroseconds() != 0) + { + if (!poll(_recvTimeout, SELECT_READ)) + throw TimeoutException(); + } } -#endif int rc; do @@ -331,13 +366,14 @@ int SocketImpl::sendTo(const void* buffer, int length, const SocketAddress& addr int SocketImpl::receiveFrom(void* buffer, int length, SocketAddress& address, int flags) { -#if defined(POCO_BROKEN_TIMEOUTS) - if (_recvTimeout.totalMicroseconds() != 0) + if (_isBrokenTimeout) { - if (!poll(_recvTimeout, SELECT_READ)) - throw TimeoutException(); + if (_recvTimeout.totalMicroseconds() != 0) + { + if (!poll(_recvTimeout, SELECT_READ)) + throw TimeoutException(); + } } -#endif char abuffer[SocketAddress::MAX_ADDRESS_LENGTH]; struct sockaddr* pSA = reinterpret_cast(abuffer); @@ -555,11 +591,11 @@ void SocketImpl::setSendTimeout(const Poco::Timespan& timeout) #if defined(_WIN32) && !defined(POCO_BROKEN_TIMEOUTS) int value = (int) timeout.totalMilliseconds(); setOption(SOL_SOCKET, SO_SNDTIMEO, value); -#elif defined(POCO_BROKEN_TIMEOUTS) - _sndTimeout = timeout; -#else +#elif !defined(POCO_BROKEN_TIMEOUTS) setOption(SOL_SOCKET, SO_SNDTIMEO, timeout); #endif + if (_isBrokenTimeout) + _sndTimeout = timeout; } @@ -570,11 +606,11 @@ Poco::Timespan SocketImpl::getSendTimeout() int value; getOption(SOL_SOCKET, SO_SNDTIMEO, value); result = Timespan::TimeDiff(value)*1000; -#elif defined(POCO_BROKEN_TIMEOUTS) - result = _sndTimeout; -#else +#elif !defined(POCO_BROKEN_TIMEOUTS) getOption(SOL_SOCKET, SO_SNDTIMEO, result); #endif + if (_isBrokenTimeout) + result = _sndTimeout; return result; } @@ -588,9 +624,9 @@ void SocketImpl::setReceiveTimeout(const Poco::Timespan& timeout) #else setOption(SOL_SOCKET, SO_RCVTIMEO, timeout); #endif -#else - _recvTimeout = timeout; #endif + if (_isBrokenTimeout) + _recvTimeout = timeout; } @@ -601,11 +637,11 @@ Poco::Timespan SocketImpl::getReceiveTimeout() int value; getOption(SOL_SOCKET, SO_RCVTIMEO, value); result = Timespan::TimeDiff(value)*1000; -#elif defined(POCO_BROKEN_TIMEOUTS) - result = _recvTimeout; -#else +#elif !defined(POCO_BROKEN_TIMEOUTS) getOption(SOL_SOCKET, SO_RCVTIMEO, result); #endif + if (_isBrokenTimeout) + result = _recvTimeout; return result; } @@ -1060,6 +1096,8 @@ void SocketImpl::error(int code, const std::string& arg) throw IOException("Broken pipe", code); case EBADF: throw IOException("Bad socket descriptor", code); + case ENOENT: + throw IOException("Not found", arg, code); #endif default: throw IOException(NumberFormatter::format(code), arg, code); diff --git a/Net/src/StreamSocket.cpp b/Net/src/StreamSocket.cpp index 3246ccb6a..598d2991c 100644 --- a/Net/src/StreamSocket.cpp +++ b/Net/src/StreamSocket.cpp @@ -39,7 +39,7 @@ StreamSocket::StreamSocket(const SocketAddress& address): Socket(new StreamSocke } -StreamSocket::StreamSocket(IPAddress::Family family): Socket(new StreamSocketImpl(family)) +StreamSocket::StreamSocket(SocketAddress::Family family): Socket(new StreamSocketImpl(family)) { } diff --git a/Net/src/StreamSocketImpl.cpp b/Net/src/StreamSocketImpl.cpp index f28633071..8116942db 100644 --- a/Net/src/StreamSocketImpl.cpp +++ b/Net/src/StreamSocketImpl.cpp @@ -26,13 +26,17 @@ StreamSocketImpl::StreamSocketImpl() } -StreamSocketImpl::StreamSocketImpl(IPAddress::Family family) +StreamSocketImpl::StreamSocketImpl(SocketAddress::Family family) { - if (family == IPAddress::IPv4) + if (family == SocketAddress::IPv4) init(AF_INET); #if defined(POCO_HAVE_IPv6) - else if (family == IPAddress::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"); } diff --git a/Net/src/TCPServer.cpp b/Net/src/TCPServer.cpp index 5659a6424..7a7282f78 100644 --- a/Net/src/TCPServer.cpp +++ b/Net/src/TCPServer.cpp @@ -28,6 +28,21 @@ 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)), @@ -120,9 +135,18 @@ void TCPServer::run() try { StreamSocket ss = _socket.acceptConnection(); - // enabe nodelay per default: OSX really needs that - ss.setNoDelay(true); - _pDispatcher->enqueue(ss); + + 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) { @@ -191,6 +215,14 @@ int TCPServer::refusedConnections() const } +void TCPServer::setConnectionFilter(const TCPServerConnectionFilter::Ptr& pConnectionFilter) +{ + poco_assert (_stopped); + + _pConnectionFilter = pConnectionFilter; +} + + std::string TCPServer::threadName(const ServerSocket& socket) { #if _WIN32_WCE == 0x0800 diff --git a/Net/src/WebSocket.cpp b/Net/src/WebSocket.cpp index f179f87f4..992e44ca1 100644 --- a/Net/src/WebSocket.cpp +++ b/Net/src/WebSocket.cpp @@ -19,7 +19,6 @@ #include "Poco/Net/HTTPClientSession.h" #include "Poco/Net/HTTPServerSession.h" #include "Poco/Net/NetException.h" -#include "Poco/Buffer.h" #include "Poco/MemoryStream.h" #include "Poco/NullStream.h" #include "Poco/BinaryWriter.h" @@ -113,6 +112,14 @@ int WebSocket::receiveFrame(void* buffer, int length, int& flags) } +int WebSocket::receiveFrame(Poco::Buffer& buffer, int& flags) +{ + int n = static_cast(impl())->receiveBytes(buffer, 0); + flags = static_cast(impl())->frameFlags(); + return n; +} + + WebSocket::Mode WebSocket::mode() const { return static_cast(impl())->mustMaskPayload() ? WS_CLIENT : WS_SERVER; diff --git a/Net/src/WebSocketImpl.cpp b/Net/src/WebSocketImpl.cpp index 573587f46..b3eb4c580 100644 --- a/Net/src/WebSocketImpl.cpp +++ b/Net/src/WebSocketImpl.cpp @@ -106,7 +106,7 @@ int WebSocketImpl::sendBytes(const void* buffer, int length, int flags) } -int WebSocketImpl::receiveBytes(void* buffer, int length, int) +int WebSocketImpl::receiveHeader(char mask[4], bool& useMask) { char header[MAX_HEADER_LENGTH]; int n = receiveNBytes(header, 2); @@ -116,82 +116,101 @@ int WebSocketImpl::receiveBytes(void* buffer, int length, int) return n; } poco_assert (n == 2); - Poco::UInt8 lengthByte = static_cast(header[1]); - int maskOffset = 0; - if (lengthByte & FRAME_FLAG_MASK) maskOffset += 4; - lengthByte &= 0x7f; - if (lengthByte > 0 || maskOffset > 0) - { - if (lengthByte + 2 + maskOffset < MAX_HEADER_LENGTH) - { - n = receiveNBytes(header + 2, lengthByte + maskOffset); - } - else - { - n = receiveNBytes(header + 2, MAX_HEADER_LENGTH - 2); - } - if (n <= 0) throw WebSocketException("Incomplete header received", WebSocket::WS_ERR_INCOMPLETE_FRAME); - n += 2; - } - Poco::MemoryInputStream istr(header, n); - Poco::BinaryReader reader(istr, Poco::BinaryReader::NETWORK_BYTE_ORDER); - Poco::UInt8 flags; - char mask[4]; - reader >> flags >> lengthByte; + Poco::UInt8 flags = static_cast(header[0]); _frameFlags = flags; - int payloadLength = 0; - int payloadOffset = 2; - if ((lengthByte & 0x7f) == 127) + Poco::UInt8 lengthByte = static_cast(header[1]); + useMask = ((lengthByte & FRAME_FLAG_MASK) != 0); + int payloadLength; + lengthByte &= 0x7f; + if (lengthByte == 127) { + n = receiveNBytes(header + 2, 8); + if (n <= 0) + { + _frameFlags = 0; + return n; + } + Poco::MemoryInputStream istr(header + 2, 8); + Poco::BinaryReader reader(istr, Poco::BinaryReader::NETWORK_BYTE_ORDER); Poco::UInt64 l; reader >> l; - if (l > length) throw WebSocketException(Poco::format("Insufficient buffer for payload size %Lu", l), WebSocket::WS_ERR_PAYLOAD_TOO_BIG); payloadLength = static_cast(l); - payloadOffset += 8; } - else if ((lengthByte & 0x7f) == 126) + else if (lengthByte == 126) { + n = receiveNBytes(header + 2, 2); + if (n <= 0) + { + _frameFlags = 0; + return n; + } + Poco::MemoryInputStream istr(header + 2, 2); + Poco::BinaryReader reader(istr, Poco::BinaryReader::NETWORK_BYTE_ORDER); Poco::UInt16 l; reader >> l; - if (l > length) throw WebSocketException(Poco::format("Insufficient buffer for payload size %hu", l), WebSocket::WS_ERR_PAYLOAD_TOO_BIG); payloadLength = static_cast(l); - payloadOffset += 2; } else { - Poco::UInt8 l = lengthByte & 0x7f; - if (l > length) throw WebSocketException(Poco::format("Insufficient buffer for payload size %u", unsigned(l)), WebSocket::WS_ERR_PAYLOAD_TOO_BIG); - payloadLength = static_cast(l); + payloadLength = lengthByte; } - if (lengthByte & FRAME_FLAG_MASK) + + if (useMask) { - reader.readRaw(mask, 4); - payloadOffset += 4; + n = receiveNBytes(mask, 4); + if (n <= 0) + { + _frameFlags = 0; + return n; + } } - int received = 0; - if (payloadOffset < n) + + return payloadLength; +} + + +int WebSocketImpl::receivePayload(char *buffer, int payloadLength, char mask[4], bool useMask) +{ + int received = receiveNBytes(reinterpret_cast(buffer), payloadLength); + if (received <= 0) throw WebSocketException("Incomplete frame received", WebSocket::WS_ERR_INCOMPLETE_FRAME); + + if (useMask) { - std::memcpy(buffer, header + payloadOffset, n - payloadOffset); - received = n - payloadOffset; - } - if (received < payloadLength) - { - n = receiveNBytes(reinterpret_cast(buffer) + received, payloadLength - received); - if (n <= 0) throw WebSocketException("Incomplete frame received", WebSocket::WS_ERR_INCOMPLETE_FRAME); - received += n; - } - if (lengthByte & FRAME_FLAG_MASK) - { - char* p = reinterpret_cast(buffer); for (int i = 0; i < received; i++) { - p[i] ^= mask[i % 4]; + buffer[i] ^= mask[i % 4]; } } return received; } +int WebSocketImpl::receiveBytes(void* buffer, int length, int) +{ + char mask[4]; + bool useMask; + int payloadLength = receiveHeader(mask, useMask); + if (payloadLength <= 0) + return payloadLength; + if (payloadLength > length) + throw WebSocketException(Poco::format("Insufficient buffer for payload size %hu", payloadLength), WebSocket::WS_ERR_PAYLOAD_TOO_BIG); + return receivePayload(reinterpret_cast(buffer), payloadLength, mask, useMask); +} + + +int WebSocketImpl::receiveBytes(Poco::Buffer& buffer, int) +{ + char mask[4]; + bool useMask; + int payloadLength = receiveHeader(mask, useMask); + if (payloadLength <= 0) + return payloadLength; + int oldSize = buffer.size(); + buffer.resize(oldSize + payloadLength); + return receivePayload(buffer.begin() + oldSize, payloadLength, mask, useMask); +} + + int WebSocketImpl::receiveNBytes(void* buffer, int bytes) { int received = receiveSomeBytes(reinterpret_cast(buffer), bytes); @@ -212,7 +231,7 @@ int WebSocketImpl::receiveNBytes(void* buffer, int bytes) int WebSocketImpl::receiveSomeBytes(char* buffer, int bytes) { - int n = static_cast(_buffer.size() - _bufferOffset); + int n = _buffer.size() - _bufferOffset; if (n > 0) { if (bytes < n) n = bytes; @@ -257,12 +276,24 @@ void WebSocketImpl::bind(const SocketAddress& address, bool reuseAddress) } +void WebSocketImpl::bind(const SocketAddress& address, bool reuseAddress, bool reusePort) +{ + throw Poco::InvalidAccessException("Cannot bind() a WebSocketImpl"); +} + + void WebSocketImpl::bind6(const SocketAddress& address, bool reuseAddress, bool ipV6Only) { throw Poco::InvalidAccessException("Cannot bind6() a WebSocketImpl"); } +void WebSocketImpl::bind6(const SocketAddress& address, bool reuseAddress, bool reusePort, bool ipV6Only) +{ + throw Poco::InvalidAccessException("Cannot bind6() a WebSocketImpl"); +} + + void WebSocketImpl::listen(int backlog) { throw Poco::InvalidAccessException("Cannot listen() on a WebSocketImpl"); diff --git a/Net/testsuite/src/DNSTest.cpp b/Net/testsuite/src/DNSTest.cpp index 9779a807d..81fbac4ea 100644 --- a/Net/testsuite/src/DNSTest.cpp +++ b/Net/testsuite/src/DNSTest.cpp @@ -37,20 +37,20 @@ DNSTest::~DNSTest() void DNSTest::testHostByName() { - HostEntry he1 = DNS::hostByName("aliastest.appinf.com"); + HostEntry he1 = DNS::hostByName("aliastest.pocoproject.org"); // different systems report different canonical names, unfortunately. - assert (he1.name() == "dnstest.appinf.com" || he1.name() == "aliastest.appinf.com"); + assert (he1.name() == "dnstest.pocoproject.org" || he1.name() == "aliastest.pocoproject.org"); #if !defined(POCO_HAVE_ADDRINFO) // getaddrinfo() does not report any aliases assert (!he1.aliases().empty()); - assert (he1.aliases()[0] == "aliastest.appinf.com"); + assert (he1.aliases()[0] == "aliastest.pocoproject.org"); #endif assert (he1.addresses().size() >= 1); assert (he1.addresses()[0].toString() == "1.2.3.4"); try { - HostEntry he1 = DNS::hostByName("nohost.appinf.com"); + HostEntry he1 = DNS::hostByName("nohost.pocoproject.org"); fail("host not found - must throw"); } catch (HostNotFoundException&) diff --git a/Net/testsuite/src/DatagramSocketTest.cpp b/Net/testsuite/src/DatagramSocketTest.cpp index 6d15104c0..6d76ef57a 100644 --- a/Net/testsuite/src/DatagramSocketTest.cpp +++ b/Net/testsuite/src/DatagramSocketTest.cpp @@ -49,7 +49,7 @@ void DatagramSocketTest::testEcho() UDPEchoServer echoServer; DatagramSocket ss; char buffer[256]; - ss.connect(SocketAddress("localhost", echoServer.port())); + ss.connect(SocketAddress("127.0.0.1", echoServer.port())); int n = ss.sendBytes("hello", 5); assert (n == 5); n = ss.receiveBytes(buffer, sizeof(buffer)); @@ -61,9 +61,9 @@ void DatagramSocketTest::testEcho() void DatagramSocketTest::testSendToReceiveFrom() { - UDPEchoServer echoServer(SocketAddress("localhost", 0)); - DatagramSocket ss; - int n = ss.sendTo("hello", 5, SocketAddress("localhost", echoServer.port())); + UDPEchoServer echoServer(SocketAddress("127.0.0.1", 0)); + DatagramSocket ss(SocketAddress::IPv4); + int n = ss.sendTo("hello", 5, SocketAddress("127.0.0.1", echoServer.port())); assert (n == 5); char buffer[256]; SocketAddress sa; @@ -76,6 +76,21 @@ void DatagramSocketTest::testSendToReceiveFrom() } +void DatagramSocketTest::testUnbound() +{ + UDPEchoServer echoServer; + DatagramSocket ss; + char buffer[256]; + ss.connect(SocketAddress("127.0.0.1", echoServer.port())); + int n = ss.sendBytes("hello", 5); + assert (n == 5); + n = ss.receiveBytes(buffer, sizeof(buffer)); + assert (n == 5); + assert (std::string(buffer, n) == "hello"); + ss.close(); +} + + void DatagramSocketTest::testBroadcast() { UDPEchoServer echoServer; @@ -134,6 +149,7 @@ CppUnit::Test* DatagramSocketTest::suite() CppUnit_addTest(pSuite, DatagramSocketTest, testEcho); CppUnit_addTest(pSuite, DatagramSocketTest, testSendToReceiveFrom); + CppUnit_addTest(pSuite, DatagramSocketTest, testUnbound); #if (POCO_OS != POCO_OS_FREE_BSD) // works only with local net bcast and very randomly CppUnit_addTest(pSuite, DatagramSocketTest, testBroadcast); #endif diff --git a/Net/testsuite/src/DatagramSocketTest.h b/Net/testsuite/src/DatagramSocketTest.h index d173d03ac..e151cca2e 100644 --- a/Net/testsuite/src/DatagramSocketTest.h +++ b/Net/testsuite/src/DatagramSocketTest.h @@ -26,6 +26,7 @@ public: void testEcho(); void testSendToReceiveFrom(); + void testUnbound(); void testBroadcast(); void setUp(); diff --git a/Net/testsuite/src/DialogSocketTest.cpp b/Net/testsuite/src/DialogSocketTest.cpp index 4957d3f79..e38f11dec 100644 --- a/Net/testsuite/src/DialogSocketTest.cpp +++ b/Net/testsuite/src/DialogSocketTest.cpp @@ -35,7 +35,7 @@ void DialogSocketTest::testDialogSocket() { EchoServer echoServer; DialogSocket ds; - ds.connect(SocketAddress("localhost", echoServer.port())); + ds.connect(SocketAddress("127.0.0.1", echoServer.port())); ds.sendMessage("Hello, world!"); std::string str; diff --git a/Net/testsuite/src/EchoServer.cpp b/Net/testsuite/src/EchoServer.cpp index 69d23a4c9..74a5370fd 100644 --- a/Net/testsuite/src/EchoServer.cpp +++ b/Net/testsuite/src/EchoServer.cpp @@ -30,6 +30,16 @@ EchoServer::EchoServer(): } +EchoServer::EchoServer(const Poco::Net::SocketAddress& address): + _socket(address), + _thread("EchoServer"), + _stop(false) +{ + _thread.start(*this); + _ready.wait(); +} + + EchoServer::~EchoServer() { _stop = true; diff --git a/Net/testsuite/src/EchoServer.h b/Net/testsuite/src/EchoServer.h index c95cb4530..d724d495a 100644 --- a/Net/testsuite/src/EchoServer.h +++ b/Net/testsuite/src/EchoServer.h @@ -27,6 +27,9 @@ public: EchoServer(); /// Creates the EchoServer. + EchoServer(const Poco::Net::SocketAddress& address); + /// Creates the EchoServer using the given address. + ~EchoServer(); /// Destroys the EchoServer. diff --git a/Net/testsuite/src/FTPClientSessionTest.cpp b/Net/testsuite/src/FTPClientSessionTest.cpp index 7dcb3f2a8..ee889189f 100644 --- a/Net/testsuite/src/FTPClientSessionTest.cpp +++ b/Net/testsuite/src/FTPClientSessionTest.cpp @@ -92,7 +92,7 @@ void FTPClientSessionTest::testLogin1() { DialogServer server; server.addResponse("220 localhost FTP ready"); - FTPClientSession session("localhost", server.port()); + FTPClientSession session("127.0.0.1", server.port()); assert (session.isOpen()); assert (!session.isLoggedIn()); login(server, session); @@ -123,7 +123,7 @@ void FTPClientSessionTest::testLogin2() server.addResponse("230 Welcome"); server.addResponse("200 Type set to I"); Poco::UInt16 serverPort = server.port(); - FTPClientSession session("localhost", serverPort, "user", "password"); + FTPClientSession session("127.0.0.1", serverPort, "user", "password"); assert (session.isOpen()); assert (session.isLoggedIn()); server.addResponse("221 Good Bye"); @@ -137,7 +137,7 @@ void FTPClientSessionTest::testLogin2() server.addResponse("331 Password required"); server.addResponse("230 Welcome"); server.addResponse("200 Type set to I"); - session.open("localhost", serverPort, "user", "password"); + session.open("127.0.0.1", serverPort, "user", "password"); assert (session.isOpen()); assert (session.isLoggedIn()); server.addResponse("221 Good Bye"); @@ -157,7 +157,7 @@ void FTPClientSessionTest::testLogin3() FTPClientSession session; assert (!session.isOpen()); assert (!session.isLoggedIn()); - session.open("localhost", server.port(), "user", "password"); + session.open("127.0.0.1", server.port(), "user", "password"); server.addResponse("221 Good Bye"); session.close(); assert (!session.isOpen()); @@ -170,7 +170,7 @@ void FTPClientSessionTest::testLoginFailed1() { DialogServer server; server.addResponse("421 localhost FTP not ready"); - FTPClientSession session("localhost", server.port()); + FTPClientSession session("127.0.0.1", server.port()); try { session.login("user", "password"); @@ -190,7 +190,7 @@ void FTPClientSessionTest::testLoginFailed2() server.addResponse("220 localhost FTP ready"); server.addResponse("331 Password required"); server.addResponse("530 Login incorrect"); - FTPClientSession session("localhost", server.port()); + FTPClientSession session("127.0.0.1", server.port()); try { session.login("user", "password"); @@ -211,7 +211,7 @@ void FTPClientSessionTest::testCommands() server.addResponse("331 Password required"); server.addResponse("230 Welcome"); server.addResponse("200 Type set to I"); - FTPClientSession session("localhost", server.port()); + FTPClientSession session("127.0.0.1", server.port()); session.login("user", "password"); std::string cmd = server.popCommand(); assert (cmd == "USER user"); @@ -340,7 +340,7 @@ void FTPClientSessionTest::testDownloadPORT() server.addResponse("331 Password required"); server.addResponse("230 Welcome"); server.addResponse("200 Type set to I"); - FTPClientSession session("localhost", server.port()); + FTPClientSession session("127.0.0.1", server.port()); session.setPassive(false); session.login("user", "password"); server.clearCommands(); @@ -371,7 +371,7 @@ void FTPClientSessionTest::testDownloadPORT() cmd = server.popCommandWait(); assert (cmd == "RETR test.txt"); - SocketAddress sa("localhost", (Poco::UInt16) port); + SocketAddress sa("127.0.0.1", (Poco::UInt16) port); DialogSocket dataSock; dataSock.connect(sa); @@ -395,7 +395,7 @@ void FTPClientSessionTest::testDownloadEPRT() server.addResponse("331 Password required"); server.addResponse("230 Welcome"); server.addResponse("200 Type set to I"); - FTPClientSession session("localhost", server.port()); + FTPClientSession session("127.0.0.1", server.port()); session.setPassive(false); session.login("user", "password"); server.clearCommands(); @@ -419,7 +419,7 @@ void FTPClientSessionTest::testDownloadEPRT() cmd = server.popCommandWait(); assert (cmd == "RETR test.txt"); - SocketAddress sa("localhost", (Poco::UInt16) port); + SocketAddress sa("127.0.0.1", (Poco::UInt16) port); DialogSocket dataSock; dataSock.connect(sa); @@ -443,7 +443,7 @@ void FTPClientSessionTest::testDownloadPASV() server.addResponse("331 Password required"); server.addResponse("230 Welcome"); server.addResponse("200 Type set to I"); - FTPClientSession session("localhost", server.port()); + FTPClientSession session("127.0.0.1", server.port()); session.login("user", "password"); server.clearCommands(); @@ -476,7 +476,7 @@ void FTPClientSessionTest::testDownloadEPSV() server.addResponse("331 Password required"); server.addResponse("230 Welcome"); server.addResponse("200 Type set to I"); - FTPClientSession session("localhost", server.port()); + FTPClientSession session("127.0.0.1", server.port()); session.login("user", "password"); server.clearCommands(); @@ -511,7 +511,7 @@ void FTPClientSessionTest::testUpload() server.addResponse("331 Password required"); server.addResponse("230 Welcome"); server.addResponse("200 Type set to I"); - FTPClientSession session("localhost", server.port()); + FTPClientSession session("127.0.0.1", server.port()); session.login("user", "password"); server.clearCommands(); @@ -544,7 +544,7 @@ void FTPClientSessionTest::testList() server.addResponse("331 Password required"); server.addResponse("230 Welcome"); server.addResponse("200 Type set to I"); - FTPClientSession session("localhost", server.port()); + FTPClientSession session("127.0.0.1", server.port()); session.login("user", "password"); server.clearCommands(); diff --git a/Net/testsuite/src/FTPStreamFactoryTest.cpp b/Net/testsuite/src/FTPStreamFactoryTest.cpp index ac148c0a0..d315dafcb 100644 --- a/Net/testsuite/src/FTPStreamFactoryTest.cpp +++ b/Net/testsuite/src/FTPStreamFactoryTest.cpp @@ -75,7 +75,7 @@ void FTPStreamFactoryTest::testDownload() URI uri; uri.setScheme("ftp"); - uri.setHost("localhost"); + uri.setHost("127.0.0.1"); uri.setPort(server.port()); uri.setPath("/test.txt;type=a"); FTPStreamFactory sf; @@ -116,7 +116,7 @@ void FTPStreamFactoryTest::testList() URI uri; uri.setScheme("ftp"); - uri.setHost("localhost"); + uri.setHost("127.0.0.1"); uri.setPort(server.port()); uri.setPath("/usr/guest/data;type=d"); FTPStreamFactory sf; @@ -157,7 +157,7 @@ void FTPStreamFactoryTest::testUserInfo() URI uri; uri.setScheme("ftp"); - uri.setHost("localhost"); + uri.setHost("127.0.0.1"); uri.setPort(server.port()); uri.setPath("/test.txt;type=a"); uri.setUserInfo("user:secret"); @@ -200,7 +200,7 @@ void FTPStreamFactoryTest::testPasswordProvider() URI uri; uri.setScheme("ftp"); - uri.setHost("localhost"); + uri.setHost("127.0.0.1"); uri.setPort(server.port()); uri.setPath("/test.txt;type=a"); uri.setUserInfo("user"); @@ -231,7 +231,7 @@ void FTPStreamFactoryTest::testMissingPasswordProvider() URI uri; uri.setScheme("ftp"); - uri.setHost("localhost"); + uri.setHost("127.0.0.1"); uri.setPort(server.port()); uri.setPath("/test.txt;type=a"); uri.setUserInfo("user"); diff --git a/Net/testsuite/src/HTMLFormTest.cpp b/Net/testsuite/src/HTMLFormTest.cpp index 6dd38f043..d77a3f94c 100644 --- a/Net/testsuite/src/HTMLFormTest.cpp +++ b/Net/testsuite/src/HTMLFormTest.cpp @@ -161,6 +161,29 @@ void HTMLFormTest::testReadUrlGET() } +void HTMLFormTest::testReadUrlGETMultiple() +{ + HTTPRequest req("GET", "/form.cgi?field1=value1&field1=value%202&field1=value%3D3&field1=value%264"); + HTMLForm form(req); + assert (form.size() == 4); + + HTMLForm::ConstIterator it = form.find("field1"); + assert (it != form.end()); + assert (it->first == "field1" && it->second == "value1"); + ++it; + assert (it != form.end()); + assert (it->first == "field1" && it->second == "value 2"); + ++it; + assert (it != form.end()); + assert (it->first == "field1" && it->second == "value=3"); + ++it; + assert (it != form.end()); + assert (it->first == "field1" && it->second == "value&4"); + ++it; + assert (it == form.end()); +} + + void HTMLFormTest::testReadUrlPOST() { HTTPRequest req("POST", "/form.cgi?field0=value0"); @@ -293,6 +316,21 @@ void HTMLFormTest::testSubmit3() } +void HTMLFormTest::testSubmit4() +{ + HTMLForm form; + form.add("field1", "value1"); + form.add("field1", "value 2"); + form.add("field1", "value=3"); + form.add("field1", "value&4"); + + HTTPRequest req("GET", "/form.cgi"); + form.prepareSubmit(req); + + assert (req.getURI() == "/form.cgi?field1=value1&field1=value%202&field1=value%3D3&field1=value%264"); +} + + void HTMLFormTest::testFieldLimitUrl() { HTTPRequest req("GET", "/form.cgi?field1=value1&field2=value%202&field3=value%3D3&field4=value%264"); @@ -369,6 +407,7 @@ CppUnit::Test* HTMLFormTest::suite() CppUnit_addTest(pSuite, HTMLFormTest, testWriteUrl); CppUnit_addTest(pSuite, HTMLFormTest, testWriteMultipart); CppUnit_addTest(pSuite, HTMLFormTest, testReadUrlGET); + CppUnit_addTest(pSuite, HTMLFormTest, testReadUrlGETMultiple); CppUnit_addTest(pSuite, HTMLFormTest, testReadUrlPOST); CppUnit_addTest(pSuite, HTMLFormTest, testReadUrlPUT); CppUnit_addTest(pSuite, HTMLFormTest, testReadUrlBOM); @@ -376,6 +415,7 @@ CppUnit::Test* HTMLFormTest::suite() CppUnit_addTest(pSuite, HTMLFormTest, testSubmit1); CppUnit_addTest(pSuite, HTMLFormTest, testSubmit2); CppUnit_addTest(pSuite, HTMLFormTest, testSubmit3); + CppUnit_addTest(pSuite, HTMLFormTest, testSubmit4); CppUnit_addTest(pSuite, HTMLFormTest, testFieldLimitUrl); CppUnit_addTest(pSuite, HTMLFormTest, testFieldLimitMultipart); diff --git a/Net/testsuite/src/HTMLFormTest.h b/Net/testsuite/src/HTMLFormTest.h index 7270a524d..f9bed7905 100644 --- a/Net/testsuite/src/HTMLFormTest.h +++ b/Net/testsuite/src/HTMLFormTest.h @@ -27,6 +27,7 @@ public: void testWriteUrl(); void testWriteMultipart(); void testReadUrlGET(); + void testReadUrlGETMultiple(); void testReadUrlPOST(); void testReadUrlPUT(); void testReadUrlBOM(); @@ -34,6 +35,7 @@ public: void testSubmit1(); void testSubmit2(); void testSubmit3(); + void testSubmit4(); void testFieldLimitUrl(); void testFieldLimitMultipart(); diff --git a/Net/testsuite/src/HTTPClientSessionTest.cpp b/Net/testsuite/src/HTTPClientSessionTest.cpp index 7a32ef1be..b591b904a 100644 --- a/Net/testsuite/src/HTTPClientSessionTest.cpp +++ b/Net/testsuite/src/HTTPClientSessionTest.cpp @@ -41,7 +41,7 @@ HTTPClientSessionTest::~HTTPClientSessionTest() void HTTPClientSessionTest::testGetSmall() { HTTPTestServer srv; - HTTPClientSession s("localhost", srv.port()); + HTTPClientSession s("127.0.0.1", srv.port()); HTTPRequest request(HTTPRequest::HTTP_GET, "/small"); s.sendRequest(request); HTTPResponse response; @@ -57,7 +57,7 @@ void HTTPClientSessionTest::testGetSmall() void HTTPClientSessionTest::testGetLarge() { HTTPTestServer srv; - HTTPClientSession s("localhost", srv.port()); + HTTPClientSession s("127.0.0.1", srv.port()); HTTPRequest request(HTTPRequest::HTTP_GET, "/large"); s.sendRequest(request); HTTPResponse response; @@ -73,7 +73,7 @@ void HTTPClientSessionTest::testGetLarge() void HTTPClientSessionTest::testHead() { HTTPTestServer srv; - HTTPClientSession s("localhost", srv.port()); + HTTPClientSession s("127.0.0.1", srv.port()); HTTPRequest request(HTTPRequest::HTTP_HEAD, "/large"); s.sendRequest(request); HTTPResponse response; @@ -88,7 +88,7 @@ void HTTPClientSessionTest::testHead() void HTTPClientSessionTest::testPostSmallIdentity() { HTTPTestServer srv; - HTTPClientSession s("localhost", srv.port()); + HTTPClientSession s("127.0.0.1", srv.port()); HTTPRequest request(HTTPRequest::HTTP_POST, "/echo"); std::string body("this is a random request body\r\n0\r\n"); request.setContentLength((int) body.length()); @@ -105,7 +105,7 @@ void HTTPClientSessionTest::testPostSmallIdentity() void HTTPClientSessionTest::testPostLargeIdentity() { HTTPTestServer srv; - HTTPClientSession s("localhost", srv.port()); + HTTPClientSession s("127.0.0.1", srv.port()); HTTPRequest request(HTTPRequest::HTTP_POST, "/echo"); std::string body(8000, 'x'); body.append("\r\n0\r\n"); @@ -123,7 +123,7 @@ void HTTPClientSessionTest::testPostLargeIdentity() void HTTPClientSessionTest::testPostSmallChunked() { HTTPTestServer srv; - HTTPClientSession s("localhost", srv.port()); + HTTPClientSession s("127.0.0.1", srv.port()); HTTPRequest request(HTTPRequest::HTTP_POST, "/echo"); std::string body("this is a random request body"); request.setChunkedTransferEncoding(true); @@ -141,7 +141,7 @@ void HTTPClientSessionTest::testPostSmallChunked() void HTTPClientSessionTest::testPostLargeChunked() { HTTPTestServer srv; - HTTPClientSession s("localhost", srv.port()); + HTTPClientSession s("127.0.0.1", srv.port()); HTTPRequest request(HTTPRequest::HTTP_POST, "/echo"); std::string body(16000, 'x'); request.setChunkedTransferEncoding(true); @@ -161,7 +161,7 @@ void HTTPClientSessionTest::testPostLargeChunked() void HTTPClientSessionTest::testPostSmallClose() { HTTPTestServer srv; - HTTPClientSession s("localhost", srv.port()); + HTTPClientSession s("127.0.0.1", srv.port()); HTTPRequest request(HTTPRequest::HTTP_POST, "/echo"); std::string body("this is a random request body"); s.sendRequest(request) << body; @@ -178,7 +178,7 @@ void HTTPClientSessionTest::testPostSmallClose() void HTTPClientSessionTest::testPostLargeClose() { HTTPTestServer srv; - HTTPClientSession s("localhost", srv.port()); + HTTPClientSession s("127.0.0.1", srv.port()); HTTPRequest request(HTTPRequest::HTTP_POST, "/echo"); std::string body(8000, 'x'); s.sendRequest(request) << body; @@ -195,7 +195,7 @@ void HTTPClientSessionTest::testPostLargeClose() void HTTPClientSessionTest::testKeepAlive() { HTTPTestServer srv; - HTTPClientSession s("localhost", srv.port()); + HTTPClientSession s("127.0.0.1", srv.port()); s.setKeepAlive(true); HTTPRequest request(HTTPRequest::HTTP_HEAD, "/keepAlive", HTTPMessage::HTTP_1_1); s.sendRequest(request); @@ -244,7 +244,7 @@ void HTTPClientSessionTest::testProxy() { HTTPTestServer srv; HTTPClientSession s("www.somehost.com"); - s.setProxy("localhost", srv.port()); + s.setProxy("127.0.0.1", srv.port()); HTTPRequest request(HTTPRequest::HTTP_GET, "/large"); s.sendRequest(request); HTTPResponse response; @@ -261,7 +261,7 @@ void HTTPClientSessionTest::testProxyAuth() { HTTPTestServer srv; HTTPClientSession s("www.somehost.com"); - s.setProxy("localhost", srv.port()); + s.setProxy("127.0.0.1", srv.port()); s.setProxyCredentials("user", "pass"); HTTPRequest request(HTTPRequest::HTTP_GET, "/large"); s.sendRequest(request); @@ -284,7 +284,7 @@ void HTTPClientSessionTest::testBypassProxy() proxyConfig.port = 80; proxyConfig.nonProxyHosts = "localhost|127\\.0\\.0\\.1"; - HTTPClientSession s1("localhost", 80); + HTTPClientSession s1("127.0.0.1", 80); s1.setProxyConfig(proxyConfig); assert (s1.bypassProxy()); @@ -298,6 +298,47 @@ void HTTPClientSessionTest::testBypassProxy() } +void HTTPClientSessionTest::testExpectContinue() +{ + HTTPTestServer srv; + HTTPClientSession s("127.0.0.1", srv.port()); + HTTPRequest request(HTTPRequest::HTTP_POST, "/expect"); + std::string body("this is a random request body\r\n0\r\n"); + request.setContentLength((int) body.length()); + request.setExpectContinue(true); + s.sendRequest(request) << body; + HTTPResponse response; + assert (s.peekResponse(response)); + assert (response.getStatus() == HTTPResponse::HTTP_CONTINUE); + std::istream& rs = s.receiveResponse(response); + assert (response.getStatus() == HTTPResponse::HTTP_OK); + assert (response.getContentLength() == body.length()); + std::ostringstream ostr; + StreamCopier::copyStream(rs, ostr); + assert (ostr.str() == body); +} + + +void HTTPClientSessionTest::testExpectContinueFail() +{ + HTTPTestServer srv; + HTTPClientSession s("127.0.0.1", srv.port()); + HTTPRequest request(HTTPRequest::HTTP_POST, "/fail"); + std::string body("this is a random request body\r\n0\r\n"); + request.setContentLength((int) body.length()); + request.setExpectContinue(true); + s.sendRequest(request) << body; + HTTPResponse response; + assert (!s.peekResponse(response)); + assert (response.getStatus() == HTTPResponse::HTTP_BAD_REQUEST); + std::istream& rs = s.receiveResponse(response); + assert (response.getStatus() == HTTPResponse::HTTP_BAD_REQUEST); + std::ostringstream ostr; + StreamCopier::copyStream(rs, ostr); + assert (ostr.str().empty()); +} + + void HTTPClientSessionTest::setUp() { } @@ -325,6 +366,8 @@ CppUnit::Test* HTTPClientSessionTest::suite() CppUnit_addTest(pSuite, HTTPClientSessionTest, testProxy); CppUnit_addTest(pSuite, HTTPClientSessionTest, testProxyAuth); CppUnit_addTest(pSuite, HTTPClientSessionTest, testBypassProxy); + CppUnit_addTest(pSuite, HTTPClientSessionTest, testExpectContinue); + CppUnit_addTest(pSuite, HTTPClientSessionTest, testExpectContinueFail); return pSuite; } diff --git a/Net/testsuite/src/HTTPClientSessionTest.h b/Net/testsuite/src/HTTPClientSessionTest.h index 9e602c9ad..dce5d634c 100644 --- a/Net/testsuite/src/HTTPClientSessionTest.h +++ b/Net/testsuite/src/HTTPClientSessionTest.h @@ -37,6 +37,8 @@ public: void testProxy(); void testProxyAuth(); void testBypassProxy(); + void testExpectContinue(); + void testExpectContinueFail(); void setUp(); void tearDown(); diff --git a/Net/testsuite/src/HTTPResponseTest.cpp b/Net/testsuite/src/HTTPResponseTest.cpp index e8ce43ae4..009cff23b 100644 --- a/Net/testsuite/src/HTTPResponseTest.cpp +++ b/Net/testsuite/src/HTTPResponseTest.cpp @@ -196,8 +196,8 @@ void HTTPResponseTest::testCookies() cookies.clear(); response2.getCookies(cookies); assert (cookies.size() == 2); - assert (((cookies[0].getName() == "name1") && (cookies[1].getName() == "name2")) || - ((cookies[0].getName() == "name2") && (cookies[1].getName() == "name1"))); + assert (cookies[0].getName() == "name1" && cookies[1].getName() == "name2" + || cookies[0].getName() == "name2" && cookies[1].getName() == "name1"); } diff --git a/Net/testsuite/src/HTTPServerTest.cpp b/Net/testsuite/src/HTTPServerTest.cpp index c4c9ee4b5..c8440916f 100644 --- a/Net/testsuite/src/HTTPServerTest.cpp +++ b/Net/testsuite/src/HTTPServerTest.cpp @@ -144,7 +144,7 @@ void HTTPServerTest::testIdentityRequest() HTTPServer srv(new RequestHandlerFactory, svs, pParams); srv.start(); - HTTPClientSession cs("localhost", svs.address().port()); + HTTPClientSession cs("127.0.0.1", svs.address().port()); std::string body(5000, 'x'); HTTPRequest request("POST", "/echoBody"); request.setContentLength((int) body.length()); @@ -167,7 +167,7 @@ void HTTPServerTest::testPutIdentityRequest() HTTPServer srv(new RequestHandlerFactory, svs, pParams); srv.start(); - HTTPClientSession cs("localhost", svs.address().port()); + HTTPClientSession cs("127.0.0.1", svs.address().port()); std::string body(5000, 'x'); HTTPRequest request("PUT", "/echoBody"); request.setContentLength((int) body.length()); @@ -190,7 +190,7 @@ void HTTPServerTest::testChunkedRequest() HTTPServer srv(new RequestHandlerFactory, svs, pParams); srv.start(); - HTTPClientSession cs("localhost", svs.address().port()); + HTTPClientSession cs("127.0.0.1", svs.address().port()); std::string body(5000, 'x'); HTTPRequest request("POST", "/echoBody"); request.setContentType("text/plain"); @@ -214,7 +214,7 @@ void HTTPServerTest::testClosedRequest() HTTPServer srv(new RequestHandlerFactory, svs, pParams); srv.start(); - HTTPClientSession cs("localhost", svs.address().port()); + HTTPClientSession cs("127.0.0.1", svs.address().port()); std::string body(5000, 'x'); HTTPRequest request("POST", "/echoBody"); request.setContentType("text/plain"); @@ -234,7 +234,7 @@ void HTTPServerTest::testIdentityRequestKeepAlive() HTTPServer srv(new RequestHandlerFactory, 8008); srv.start(); - HTTPClientSession cs("localhost", srv.socket().address().port()); + HTTPClientSession cs("127.0.0.1", srv.socket().address().port()); cs.setKeepAlive(true); std::string body(5000, 'x'); HTTPRequest request("POST", "/echoBody", HTTPMessage::HTTP_1_1); @@ -265,7 +265,7 @@ void HTTPServerTest::testChunkedRequestKeepAlive() HTTPServer srv(new RequestHandlerFactory, 8009); srv.start(); - HTTPClientSession cs("localhost", srv.socket().address().port()); + HTTPClientSession cs("127.0.0.1", srv.socket().address().port()); cs.setKeepAlive(true); std::string body(5000, 'x'); HTTPRequest request("POST", "/echoBody", HTTPMessage::HTTP_1_1); @@ -297,7 +297,7 @@ void HTTPServerTest::testClosedRequestKeepAlive() HTTPServer srv(new RequestHandlerFactory, 8010); srv.start(); - HTTPClientSession cs("localhost", srv.socket().address().port()); + HTTPClientSession cs("127.0.0.1", srv.socket().address().port()); std::string body(5000, 'x'); HTTPRequest request("POST", "/echoBody"); request.setContentType("text/plain"); @@ -322,7 +322,7 @@ void HTTPServerTest::testMaxKeepAlive() HTTPServer srv(new RequestHandlerFactory, svs, pParams); srv.start(); - HTTPClientSession cs("localhost", svs.address().port()); + HTTPClientSession cs("127.0.0.1", svs.address().port()); cs.setKeepAlive(true); HTTPRequest request("POST", "/echoBody", HTTPMessage::HTTP_1_1); request.setContentType("text/plain"); @@ -378,7 +378,7 @@ void HTTPServerTest::testKeepAliveTimeout() HTTPServer srv(new RequestHandlerFactory, svs, pParams); srv.start(); - HTTPClientSession cs("localhost", svs.address().port()); + HTTPClientSession cs("127.0.0.1", svs.address().port()); cs.setKeepAlive(true); cs.setKeepAliveTimeout(Poco::Timespan(2, 0)); HTTPRequest request("POST", "/echoBody", HTTPMessage::HTTP_1_1); @@ -422,7 +422,7 @@ void HTTPServerTest::test100Continue() HTTPServer srv(new RequestHandlerFactory, svs, pParams); srv.start(); - HTTPClientSession cs("localhost", svs.address().port()); + HTTPClientSession cs("127.0.0.1", svs.address().port()); std::string body(5000, 'x'); HTTPRequest request("POST", "/echoBody"); request.setContentLength((int) body.length()); @@ -446,7 +446,7 @@ void HTTPServerTest::testRedirect() HTTPServer srv(new RequestHandlerFactory, svs, pParams); srv.start(); - HTTPClientSession cs("localhost", svs.address().port()); + HTTPClientSession cs("127.0.0.1", svs.address().port()); HTTPRequest request("GET", "/redirect"); cs.sendRequest(request); HTTPResponse response; @@ -466,7 +466,7 @@ void HTTPServerTest::testAuth() HTTPServer srv(new RequestHandlerFactory, svs, pParams); srv.start(); - HTTPClientSession cs("localhost", svs.address().port()); + HTTPClientSession cs("127.0.0.1", svs.address().port()); HTTPRequest request("GET", "/auth"); cs.sendRequest(request); HTTPResponse response; @@ -486,7 +486,7 @@ void HTTPServerTest::testNotImpl() HTTPServer srv(new RequestHandlerFactory, svs, pParams); srv.start(); - HTTPClientSession cs("localhost", svs.address().port()); + HTTPClientSession cs("127.0.0.1", svs.address().port()); HTTPRequest request("GET", "/notImpl"); cs.sendRequest(request); HTTPResponse response; @@ -505,7 +505,7 @@ void HTTPServerTest::testBuffer() HTTPServer srv(new RequestHandlerFactory, svs, pParams); srv.start(); - HTTPClientSession cs("localhost", svs.address().port()); + HTTPClientSession cs("127.0.0.1", svs.address().port()); HTTPRequest request("GET", "/buffer"); cs.sendRequest(request); HTTPResponse response; diff --git a/Net/testsuite/src/HTTPStreamFactoryTest.cpp b/Net/testsuite/src/HTTPStreamFactoryTest.cpp index ed15b1df1..08b72cfea 100644 --- a/Net/testsuite/src/HTTPStreamFactoryTest.cpp +++ b/Net/testsuite/src/HTTPStreamFactoryTest.cpp @@ -42,7 +42,7 @@ void HTTPStreamFactoryTest::testNoRedirect() { HTTPTestServer server; HTTPStreamFactory factory; - URI uri("http://localhost/large"); + URI uri("http://127.0.0.1/large"); uri.setPort(server.port()); #ifndef POCO_ENABLE_CPP11 std::auto_ptr pStr(factory.open(uri)); @@ -59,7 +59,7 @@ void HTTPStreamFactoryTest::testEmptyPath() { HTTPTestServer server; HTTPStreamFactory factory; - URI uri("http://localhost"); + URI uri("http://127.0.0.1"); uri.setPort(server.port()); #ifndef POCO_ENABLE_CPP11 std::auto_ptr pStr(factory.open(uri)); @@ -77,7 +77,7 @@ void HTTPStreamFactoryTest::testRedirect() HTTPTestServer server; Poco::URIStreamOpener opener; opener.registerStreamFactory("http", new HTTPStreamFactory); - URI uri("http://localhost/redirect"); + URI uri("http://127.0.0.1/redirect"); uri.setPort(server.port()); #ifndef POCO_ENABLE_CPP11 std::auto_ptr pStr(opener.open(uri)); @@ -93,7 +93,7 @@ void HTTPStreamFactoryTest::testRedirect() void HTTPStreamFactoryTest::testProxy() { HTTPTestServer server; - HTTPStreamFactory factory("localhost", server.port()); + HTTPStreamFactory factory("127.0.0.1", server.port()); URI uri("http://www.somehost.com/large"); #ifndef POCO_ENABLE_CPP11 std::auto_ptr pStr(factory.open(uri)); @@ -110,7 +110,7 @@ void HTTPStreamFactoryTest::testError() { HTTPTestServer server; HTTPStreamFactory factory; - URI uri("http://localhost/notfound"); + URI uri("http://127.0.0.1/notfound"); uri.setPort(server.port()); try { diff --git a/Net/testsuite/src/HTTPTestServer.cpp b/Net/testsuite/src/HTTPTestServer.cpp index 93a33ec37..342192d44 100644 --- a/Net/testsuite/src/HTTPTestServer.cpp +++ b/Net/testsuite/src/HTTPTestServer.cpp @@ -140,6 +140,37 @@ std::string HTTPTestServer::handleRequest() const if (_lastRequest.substr(0, 3) == "GET") response.append(body); } + else if (_lastRequest.substr(0, 12) == "POST /expect") + { + std::string::size_type pos = _lastRequest.find("\r\n\r\n"); + pos += 4; + std::string body = _lastRequest.substr(pos); + response.append("HTTP/1.1 100 Continue\r\n\r\n"); + response.append("HTTP/1.1 200 OK\r\n"); + response.append("Content-Type: text/plain\r\n"); + if (_lastRequest.find("Content-Length") != std::string::npos) + { + response.append("Content-Length: "); + response.append(NumberFormatter::format((int) body.size())); + response.append("\r\n"); + } + else if (_lastRequest.find("chunked") != std::string::npos) + { + response.append("Transfer-Encoding: chunked\r\n"); + } + response.append("Connection: Close\r\n"); + response.append("\r\n"); + response.append(body); + } + else if (_lastRequest.substr(0, 10) == "POST /fail") + { + std::string::size_type pos = _lastRequest.find("\r\n\r\n"); + pos += 4; + std::string body = _lastRequest.substr(pos); + response.append("HTTP/1.1 400 Bad Request\r\n"); + response.append("Connection: Close\r\n"); + response.append("\r\n"); + } else if (_lastRequest.substr(0, 4) == "POST") { std::string::size_type pos = _lastRequest.find("\r\n\r\n"); diff --git a/Net/testsuite/src/ICMPClientTest.cpp b/Net/testsuite/src/ICMPClientTest.cpp index 6c1472d58..a8e94fbbd 100644 --- a/Net/testsuite/src/ICMPClientTest.cpp +++ b/Net/testsuite/src/ICMPClientTest.cpp @@ -46,9 +46,9 @@ ICMPClientTest::~ICMPClientTest() void ICMPClientTest::testPing() { - assert(ICMPClient::pingIPv4("localhost") > 0); + assert(ICMPClient::pingIPv4("127.0.0.1") > 0); - assert(_icmpClient.ping("localhost") > 0); + assert(_icmpClient.ping("127.0.0.1") > 0); assert(_icmpClient.ping("www.appinf.com", 4) > 0); // warning: may fail depending on the existence of the addresses at test site diff --git a/Net/testsuite/src/MailMessageTest.cpp b/Net/testsuite/src/MailMessageTest.cpp index 889d82b27..87d20bfba 100644 --- a/Net/testsuite/src/MailMessageTest.cpp +++ b/Net/testsuite/src/MailMessageTest.cpp @@ -429,6 +429,42 @@ void MailMessageTest::testReadMultiPart() } +void MailMessageTest::testReadMultiPartWithAttachmentNames() +{ + std::istringstream istr( + "Content-Type: multipart/mixed; boundary=MIME_boundary_01234567\r\n" + "Date: Thu, 1 Jan 1970 00:00:00 GMT\r\n" + "From: poco@appinf.com\r\n" + "Mime-Version: 1.0\r\n" + "Subject: Test Message\r\n" + "To: John Doe \r\n" + "\r\n" + "\r\n" + "--MIME_boundary_01234567\r\n" + "Content-Disposition: inline\r\n" + "Content-Transfer-Encoding: 8bit\r\n" + "Content-Type: text/plain\r\n" + "\r\n" + "Hello World!\r\n" + "\r\n" + "--MIME_boundary_01234567\r\n" + "Content-Disposition: attachment; filename=sample.dat\r\n" + "Content-Transfer-Encoding: base64\r\n" + "Content-Type: application/octet-stream; name=sample\r\n" + "\r\n" + "VGhpcyBpcyBzb21lIGJpbmFyeSBkYXRhLiBSZWFsbHku\r\n" + "--MIME_boundary_01234567--\r\n" + ); + + MailMessage message; + message.read(istr); + + assert (message.parts().size() == 2); + assert (message.parts()[1].name == "sample"); + assert (message.parts()[1].pSource->filename() == "sample.dat"); +} + + void MailMessageTest::testReadMultiPartDefaultTransferEncoding() { std::istringstream istr( diff --git a/Net/testsuite/src/MailMessageTest.h b/Net/testsuite/src/MailMessageTest.h index 4913c9b0f..52c8a20b2 100644 --- a/Net/testsuite/src/MailMessageTest.h +++ b/Net/testsuite/src/MailMessageTest.h @@ -35,6 +35,7 @@ public: void testReadQP(); void testRead8Bit(); void testReadMultiPart(); + void testReadMultiPartWithAttachmentNames(); void testReadMultiPartDefaultTransferEncoding(); void testEncodeWord(); diff --git a/Net/testsuite/src/MessageHeaderTest.cpp b/Net/testsuite/src/MessageHeaderTest.cpp index dd847c387..649b63b8f 100644 --- a/Net/testsuite/src/MessageHeaderTest.cpp +++ b/Net/testsuite/src/MessageHeaderTest.cpp @@ -360,6 +360,23 @@ void MessageHeaderTest::testFieldLimit() } +void MessageHeaderTest::testDecodeWord() +{ + std::string coded("this is pure ASCII"); + std::string decoded = MessageHeader::decodeWord(coded, "ISO-8859-1"); + assert(decoded == coded); + + coded = "(=?ISO-8859-1?Q?a?= =?ISO-8859-1?Q?b?=)"; + decoded = MessageHeader::decodeWord(coded, "ISO-8859-1"); + assert(decoded == "(a b)"); + + coded = "Hello =?UTF-8?B?RnJhbmNpcw==?=, good bye"; + decoded = MessageHeader::decodeWord(coded, "ISO-8859-1"); + assert(decoded == "Hello Francis, good bye"); +} + + + void MessageHeaderTest::setUp() { } @@ -390,6 +407,7 @@ CppUnit::Test* MessageHeaderTest::suite() CppUnit_addTest(pSuite, MessageHeaderTest, testSplitElements); CppUnit_addTest(pSuite, MessageHeaderTest, testSplitParameters); CppUnit_addTest(pSuite, MessageHeaderTest, testFieldLimit); + CppUnit_addTest(pSuite, MessageHeaderTest, testDecodeWord); return pSuite; } diff --git a/Net/testsuite/src/MessageHeaderTest.h b/Net/testsuite/src/MessageHeaderTest.h index 39a7563d1..e6f017436 100644 --- a/Net/testsuite/src/MessageHeaderTest.h +++ b/Net/testsuite/src/MessageHeaderTest.h @@ -40,6 +40,7 @@ public: void testSplitElements(); void testSplitParameters(); void testFieldLimit(); + void testDecodeWord(); void setUp(); void tearDown(); diff --git a/Net/testsuite/src/MulticastSocketTest.cpp b/Net/testsuite/src/MulticastSocketTest.cpp index 49fa174e5..f03a2f1a7 100644 --- a/Net/testsuite/src/MulticastSocketTest.cpp +++ b/Net/testsuite/src/MulticastSocketTest.cpp @@ -48,7 +48,7 @@ MulticastSocketTest::~MulticastSocketTest() void MulticastSocketTest::testMulticast() { MulticastEchoServer echoServer; - MulticastSocket ms; + MulticastSocket ms(SocketAddress::IPv4); int n = ms.sendTo("hello", 5, echoServer.group()); assert (n == 5); char buffer[256]; diff --git a/Net/testsuite/src/NetworkInterfaceTest.cpp b/Net/testsuite/src/NetworkInterfaceTest.cpp index 1f0d90be1..27b5e66bb 100644 --- a/Net/testsuite/src/NetworkInterfaceTest.cpp +++ b/Net/testsuite/src/NetworkInterfaceTest.cpp @@ -63,11 +63,11 @@ void NetworkInterfaceTest::testMap() std::cout << std::endl << "----------" << std::endl; std::cout << "Address " << counter << std::endl; std::cout << "----------" << std::endl; - std::cout << "Address: " << ipIt->get().toString() << std::endl; + std::cout << "Address: " << ipIt->get() << std::endl; IPAddress addr = ipIt->get(); - if (!addr.isWildcard()) std::cout << "Subnet: " << addr.toString() << " (/" << addr.prefixLength() << ")" << std::endl; + if (!addr.isWildcard()) std::cout << "Subnet: " << addr << " (/" << addr.prefixLength() << ")" << std::endl; addr = ipIt->get(); - if (!addr.isWildcard()) std::cout << "Broadcast: " << addr.toString() << std::endl; + if (!addr.isWildcard()) std::cout << "Broadcast: " << addr << std::endl; } std::cout << "=============" << std::endl << std::endl; @@ -98,11 +98,11 @@ void NetworkInterfaceTest::testList() List::const_iterator ipEnd = ipList.end(); for (int counter = 0; ipIt != ipEnd; ++ipIt, ++counter) { - std::cout << "IP Address: " << ipIt->get().toString() << std::endl; + std::cout << "IP Address: " << ipIt->get() << std::endl; IPAddress addr = ipIt->get(); - if (!addr.isWildcard()) std::cout << "Subnet: " << ipIt->get().toString() << " (/" << ipIt->get().prefixLength() << ")" << std::endl; + if (!addr.isWildcard()) std::cout << "Subnet: " << ipIt->get() << " (/" << ipIt->get().prefixLength() << ")" << std::endl; addr = ipIt->get(); - if (!addr.isWildcard()) std::cout << "Broadcast: " << ipIt->get().toString() << std::endl; + if (!addr.isWildcard()) std::cout << "Broadcast: " << ipIt->get() << std::endl; } std::cout << "==============" << std::endl << std::endl; @@ -178,7 +178,7 @@ void NetworkInterfaceTest::testMapIpOnly() { assert(it->second.supportsIPv4() || it->second.supportsIPv6()); std::cout << "Interface: (" << it->second.index() << ")" << std::endl; - std::cout << "Address: " << it->second.address().toString() << std::endl; + std::cout << "Address: " << it->second.address() << std::endl; NetworkInterface::MACAddress mac(it->second.macAddress()); if (!mac.empty() && (it->second.type() != NetworkInterface::NI_TYPE_SOFTWARE_LOOPBACK)) std::cout << "MAC Address:" << mac << std::endl; diff --git a/Net/testsuite/src/POP3ClientSessionTest.cpp b/Net/testsuite/src/POP3ClientSessionTest.cpp index bfc9cba94..999805c7b 100644 --- a/Net/testsuite/src/POP3ClientSessionTest.cpp +++ b/Net/testsuite/src/POP3ClientSessionTest.cpp @@ -40,7 +40,7 @@ void POP3ClientSessionTest::testLogin() server.addResponse("+OK USER"); server.addResponse("+OK PASS"); server.addResponse("+OK QUIT"); - POP3ClientSession session("localhost", server.port()); + POP3ClientSession session("127.0.0.1", server.port()); session.login("user", "secret"); std::string cmd = server.popCommand(); assert (cmd == "USER user"); @@ -59,7 +59,7 @@ void POP3ClientSessionTest::testLoginFail() server.addResponse("+OK USER"); server.addResponse("-ERR PASS"); server.addResponse("+OK QUIT"); - POP3ClientSession session("localhost", server.port()); + POP3ClientSession session("127.0.0.1", server.port()); try { session.login("user", "secret"); @@ -80,7 +80,7 @@ void POP3ClientSessionTest::testMessageCount() server.addResponse("+OK PASS"); server.addResponse("+OK 42 12345"); server.addResponse("+OK QUIT"); - POP3ClientSession session("localhost", server.port()); + POP3ClientSession session("127.0.0.1", server.port()); session.login("user", "secret"); server.clearCommands(); int n = session.messageCount(); @@ -105,7 +105,7 @@ void POP3ClientSessionTest::testList() ".\r\n" ); server.addResponse("+OK QUIT"); - POP3ClientSession session("localhost", server.port()); + POP3ClientSession session("127.0.0.1", server.port()); session.login("user", "secret"); server.clearCommands(); std::vector infos; @@ -144,7 +144,7 @@ void POP3ClientSessionTest::testRetrieveMessage() ".\r\n" ); server.addResponse("+OK QUIT"); - POP3ClientSession session("localhost", server.port()); + POP3ClientSession session("127.0.0.1", server.port()); session.login("user", "secret"); server.clearCommands(); MailMessage message; @@ -180,7 +180,7 @@ void POP3ClientSessionTest::testRetrieveHeader() "." ); server.addResponse("+OK QUIT"); - POP3ClientSession session("localhost", server.port()); + POP3ClientSession session("127.0.0.1", server.port()); session.login("user", "secret"); server.clearCommands(); MessageHeader header; @@ -223,7 +223,7 @@ void POP3ClientSessionTest::testRetrieveMessages() "." ); server.addResponse("+OK QUIT"); - POP3ClientSession session("localhost", server.port()); + POP3ClientSession session("127.0.0.1", server.port()); session.login("user", "secret"); server.clearCommands(); MessageHeader header; @@ -259,7 +259,7 @@ void POP3ClientSessionTest::testDeleteMessage() server.addResponse("+OK PASS"); server.addResponse("+OK DELETED"); server.addResponse("+OK QUIT"); - POP3ClientSession session("localhost", server.port()); + POP3ClientSession session("127.0.0.1", server.port()); session.login("user", "secret"); server.clearCommands(); session.deleteMessage(42); diff --git a/Net/testsuite/src/RawSocketTest.cpp b/Net/testsuite/src/RawSocketTest.cpp index 3937b3557..146b9ab10 100644 --- a/Net/testsuite/src/RawSocketTest.cpp +++ b/Net/testsuite/src/RawSocketTest.cpp @@ -43,7 +43,7 @@ RawSocketTest::~RawSocketTest() void RawSocketTest::testEchoIPv4() { - SocketAddress sa("localhost", 0); + SocketAddress sa("127.0.0.1", 0); RawSocket rs(IPAddress::IPv4); rs.connect(sa); @@ -68,7 +68,7 @@ void RawSocketTest::testSendToReceiveFromIPv4() { RawSocket rs(IPAddress::IPv4); - int n = rs.sendTo("hello", 5, SocketAddress("localhost", 0)); + int n = rs.sendTo("hello", 5, SocketAddress("127.0.0.1", 0)); assert (n == 5); char buffer[256] = ""; diff --git a/Net/testsuite/src/SMTPClientSessionTest.cpp b/Net/testsuite/src/SMTPClientSessionTest.cpp index 307670887..5263afd14 100644 --- a/Net/testsuite/src/SMTPClientSessionTest.cpp +++ b/Net/testsuite/src/SMTPClientSessionTest.cpp @@ -40,7 +40,7 @@ void SMTPClientSessionTest::testLoginEHLO() server.addResponse("220 localhost SMTP ready"); server.addResponse("250 Hello localhost"); server.addResponse("221 Bye"); - SMTPClientSession session("localhost", server.port()); + SMTPClientSession session("127.0.0.1", server.port()); session.login("localhost"); std::string cmd = server.popCommand(); assert (cmd == "EHLO localhost"); @@ -57,7 +57,7 @@ void SMTPClientSessionTest::testLoginHELO() server.addResponse("500 EHLO not understood"); server.addResponse("250 Hello localhost"); server.addResponse("221 Bye"); - SMTPClientSession session("localhost", server.port()); + SMTPClientSession session("127.0.0.1", server.port()); session.login("localhost"); std::string cmd = server.popCommand(); assert (cmd == "EHLO localhost"); @@ -74,7 +74,7 @@ void SMTPClientSessionTest::testLoginFailed() DialogServer server; server.addResponse("500 No SMTP service here"); server.addResponse("221 Bye"); - SMTPClientSession session("localhost", server.port()); + SMTPClientSession session("127.0.0.1", server.port()); try { session.login("localhost"); @@ -97,7 +97,7 @@ void SMTPClientSessionTest::testSend() server.addResponse("354 Send data"); server.addResponse("250 OK"); server.addResponse("221 Bye"); - SMTPClientSession session("localhost", server.port()); + SMTPClientSession session("127.0.0.1", server.port()); session.login("localhost"); MailMessage message; @@ -151,7 +151,7 @@ void SMTPClientSessionTest::testSendMultiRecipient() server.addResponse("250 OK"); server.addResponse("250 OK"); server.addResponse("221 Bye"); - SMTPClientSession session("localhost", server.port()); + SMTPClientSession session("127.0.0.1", server.port()); session.login("localhost"); MailMessage message; @@ -216,7 +216,7 @@ void SMTPClientSessionTest::testMultiSeparateRecipient() server.addResponse("250 OK"); server.addResponse("250 OK"); server.addResponse("221 Bye"); - SMTPClientSession session("localhost", server.port()); + SMTPClientSession session("127.0.0.1", server.port()); session.login("localhost"); MailMessage message; @@ -283,7 +283,7 @@ void SMTPClientSessionTest::testSendFailed() server.addResponse("354 Send data"); server.addResponse("500 Error"); server.addResponse("221 Bye"); - SMTPClientSession session("localhost", server.port()); + SMTPClientSession session("127.0.0.1", server.port()); session.login("localhost"); MailMessage message; diff --git a/Net/testsuite/src/SocketAddressTest.cpp b/Net/testsuite/src/SocketAddressTest.cpp index ba10b680b..a5f7d9ca2 100644 --- a/Net/testsuite/src/SocketAddressTest.cpp +++ b/Net/testsuite/src/SocketAddressTest.cpp @@ -21,6 +21,7 @@ using Poco::Net::InvalidAddressException; using Poco::Net::HostNotFoundException; using Poco::Net::ServiceNotFoundException; using Poco::Net::NoAddressFoundException; +using Poco::Net::AddressFamilyMismatchException; using Poco::InvalidArgumentException; @@ -41,8 +42,11 @@ void SocketAddressTest::testSocketAddress() assert (wild.port() == 0); SocketAddress sa1("192.168.1.100", 100); + assert (sa1.af() == AF_INET); + assert (sa1.family() == SocketAddress::IPv4); assert (sa1.host().toString() == "192.168.1.100"); assert (sa1.port() == 100); + assert (sa1.toString() == "192.168.1.100:100"); SocketAddress sa2("192.168.1.100", "100"); assert (sa2.host().toString() == "192.168.1.100"); @@ -63,7 +67,7 @@ void SocketAddressTest::testSocketAddress() { } - SocketAddress sa4("www.appinf.com", 80); + SocketAddress sa4("pocoproject.org", 80); assert (sa4.host().toString() == "162.209.7.4"); assert (sa4.port() == 80); @@ -113,6 +117,24 @@ void SocketAddressTest::testSocketAddress() catch (InvalidArgumentException&) { } + + SocketAddress sa10("www6.pocoproject.org", 80); + assert (sa10.host().toString() == "162.209.7.4" || sa10.host().toString() == "[2001:4801:7819:74:be76:4eff:fe10:6b73]"); + + SocketAddress sa11(SocketAddress::IPv4, "www6.pocoproject.org", 80); + assert (sa11.host().toString() == "162.209.7.4"); + +#ifdef POCO_HAVE_IPv6 + try + { + SocketAddress sa12(SocketAddress::IPv6, "www6.pocoproject.org", 80); + assert (sa12.host().toString() == "2001:4801:7819:74:be76:4eff:fe10:6b73"); + } + catch (AddressFamilyMismatchException&) + { + // may happen if no IPv6 address is configured on the system + } +#endif } @@ -133,6 +155,42 @@ void SocketAddressTest::testSocketRelationals() void SocketAddressTest::testSocketAddress6() { #ifdef POCO_HAVE_IPv6 + SocketAddress sa1("FE80::E6CE:8FFF:FE4A:EDD0", 100); + assert (sa1.af() == AF_INET6); + assert (sa1.family() == SocketAddress::IPv6); + assert (sa1.host().toString() == "fe80::e6ce:8fff:fe4a:edd0"); + assert (sa1.port() == 100); + assert (sa1.toString() == "[fe80::e6ce:8fff:fe4a:edd0]:100"); + + SocketAddress sa2("[FE80::E6CE:8FFF:FE4A:EDD0]:100"); + assert (sa2.af() == AF_INET6); + assert (sa2.family() == SocketAddress::IPv6); + assert (sa2.host().toString() == "fe80::e6ce:8fff:fe4a:edd0"); + assert (sa2.port() == 100); + assert (sa2.toString() == "[fe80::e6ce:8fff:fe4a:edd0]:100"); +#endif +} + + +void SocketAddressTest::testSocketAddressUnixLocal() +{ +#ifdef POCO_OS_FAMILY_UNIX + SocketAddress sa1(SocketAddress::UNIX_LOCAL, "/tmp/sock1"); + assert (sa1.af() == AF_UNIX); + assert (sa1.family() == SocketAddress::UNIX_LOCAL); + assert (sa1.toString() == "/tmp/sock1"); + + SocketAddress sa2(SocketAddress::UNIX_LOCAL, "/tmp/sock2"); + assert (sa1 != sa2); + assert (sa1 < sa2); + + SocketAddress sa3(SocketAddress::UNIX_LOCAL, "/tmp/sock1"); + assert (sa1 == sa3); + assert (!(sa1 < sa3)); + + SocketAddress sa4("/tmp/sock1"); + assert (sa1 == sa4); + assert (sa4.toString() == "/tmp/sock1"); #endif } @@ -154,6 +212,7 @@ CppUnit::Test* SocketAddressTest::suite() CppUnit_addTest(pSuite, SocketAddressTest, testSocketAddress); CppUnit_addTest(pSuite, SocketAddressTest, testSocketRelationals); CppUnit_addTest(pSuite, SocketAddressTest, testSocketAddress6); + CppUnit_addTest(pSuite, SocketAddressTest, testSocketAddressUnixLocal); return pSuite; } diff --git a/Net/testsuite/src/SocketAddressTest.h b/Net/testsuite/src/SocketAddressTest.h index 78c94784d..0ff991e2f 100644 --- a/Net/testsuite/src/SocketAddressTest.h +++ b/Net/testsuite/src/SocketAddressTest.h @@ -27,6 +27,7 @@ public: void testSocketAddress(); void testSocketRelationals(); void testSocketAddress6(); + void testSocketAddressUnixLocal(); void setUp(); void tearDown(); diff --git a/Net/testsuite/src/SocketReactorTest.cpp b/Net/testsuite/src/SocketReactorTest.cpp index 9849f654b..54653fb25 100644 --- a/Net/testsuite/src/SocketReactorTest.cpp +++ b/Net/testsuite/src/SocketReactorTest.cpp @@ -312,7 +312,7 @@ void SocketReactorTest::testSocketReactor() ServerSocket ss(ssa); SocketReactor reactor; SocketAcceptor acceptor(ss, reactor); - SocketAddress sa("localhost", ss.address().port()); + SocketAddress sa("127.0.0.1", ss.address().port()); SocketConnector connector(sa, reactor); ClientServiceHandler::setOnce(true); ClientServiceHandler::resetData(); @@ -332,7 +332,7 @@ void SocketReactorTest::testSetSocketReactor() SocketReactor reactor; SocketAcceptor acceptor(ss); acceptor.setReactor(reactor); - SocketAddress sa("localhost", ss.address().port()); + SocketAddress sa("127.0.0.1", ss.address().port()); SocketConnector connector(sa, reactor); ClientServiceHandler::setOnce(true); ClientServiceHandler::resetData(); @@ -351,7 +351,7 @@ void SocketReactorTest::testParallelSocketReactor() ServerSocket ss(ssa); SocketReactor reactor; ParallelSocketAcceptor acceptor(ss, reactor); - SocketAddress sa("localhost", ss.address().port()); + SocketAddress sa("127.0.0.1", ss.address().port()); SocketConnector connector1(sa, reactor); SocketConnector connector2(sa, reactor); SocketConnector connector3(sa, reactor); @@ -388,7 +388,7 @@ void SocketReactorTest::testSocketConnectorTimeout() SocketAddress ssa; ServerSocket ss(ssa); SocketReactor reactor; - SocketAddress sa("localhost", ss.address().port()); + SocketAddress sa("127.0.0.1", ss.address().port()); SocketConnector connector(sa, reactor); reactor.run(); assert (ClientServiceHandler::timeout()); diff --git a/Net/testsuite/src/SocketStreamTest.cpp b/Net/testsuite/src/SocketStreamTest.cpp index 93df11d9d..2e685ca0f 100644 --- a/Net/testsuite/src/SocketStreamTest.cpp +++ b/Net/testsuite/src/SocketStreamTest.cpp @@ -47,7 +47,7 @@ void SocketStreamTest::testStreamEcho() { EchoServer echoServer; StreamSocket ss; - ss.connect(SocketAddress("localhost", echoServer.port())); + ss.connect(SocketAddress("127.0.0.1", echoServer.port())); SocketStream str(ss); str << "hello"; assert (str.good()); @@ -70,7 +70,7 @@ void SocketStreamTest::testLargeStreamEcho() const int msgSize = 64000; EchoServer echoServer; StreamSocket ss; - ss.connect(SocketAddress("localhost", echoServer.port())); + ss.connect(SocketAddress("127.0.0.1", echoServer.port())); SocketStream str(ss); ss.setSendBufferSize(msgSize); ss.setReceiveBufferSize(msgSize); @@ -98,7 +98,7 @@ void SocketStreamTest::testEOF() { EchoServer echoServer; - ss.connect(SocketAddress("localhost", echoServer.port())); + ss.connect(SocketAddress("127.0.0.1", echoServer.port())); str << "hello"; assert (str.good()); str.flush(); diff --git a/Net/testsuite/src/SocketTest.cpp b/Net/testsuite/src/SocketTest.cpp index 3d54b0e0f..d02233cb6 100644 --- a/Net/testsuite/src/SocketTest.cpp +++ b/Net/testsuite/src/SocketTest.cpp @@ -21,6 +21,7 @@ #include "Poco/Buffer.h" #include "Poco/FIFOBuffer.h" #include "Poco/Delegate.h" +#include "Poco/File.h" #include @@ -52,7 +53,7 @@ void SocketTest::testEcho() { EchoServer echoServer; StreamSocket ss; - ss.connect(SocketAddress("localhost", echoServer.port())); + ss.connect(SocketAddress("127.0.0.1", echoServer.port())); int n = ss.sendBytes("hello", 5); assert (n == 5); char buffer[256]; @@ -67,7 +68,7 @@ void SocketTest::testPoll() { EchoServer echoServer; StreamSocket ss; - ss.connect(SocketAddress("localhost", echoServer.port())); + ss.connect(SocketAddress("127.0.0.1", echoServer.port())); Stopwatch sw; sw.start(); Timespan timeout(1000000); @@ -92,7 +93,7 @@ void SocketTest::testAvailable() { EchoServer echoServer; StreamSocket ss; - ss.connect(SocketAddress("localhost", echoServer.port())); + ss.connect(SocketAddress("127.0.0.1", echoServer.port())); Timespan timeout(1000000); ss.sendBytes("hello", 5); char buffer[256]; @@ -132,7 +133,7 @@ void SocketTest::testFIFOBuffer() EchoServer echoServer; StreamSocket ss; - ss.connect(SocketAddress("localhost", echoServer.port())); + ss.connect(SocketAddress("127.0.0.1", echoServer.port())); int n = ss.sendBytes(f); assert (n == 5); assert(1 == _notToReadable); @@ -169,7 +170,7 @@ void SocketTest::testConnect() serv.listen(); StreamSocket ss; Timespan timeout(250000); - ss.connect(SocketAddress("localhost", serv.address().port()), timeout); + ss.connect(SocketAddress("127.0.0.1", serv.address().port()), timeout); } @@ -184,7 +185,7 @@ void SocketTest::testConnectRefused() Timespan timeout(250000); try { - ss.connect(SocketAddress("localhost", port)); + ss.connect(SocketAddress("127.0.0.1", port)); fail("connection refused - must throw"); } catch (ConnectionRefusedException&) @@ -204,7 +205,7 @@ void SocketTest::testConnectRefusedNB() Timespan timeout(2, 0); try { - ss.connect(SocketAddress("localhost", port), timeout); + ss.connect(SocketAddress("127.0.0.1", port), timeout); fail("connection refused - must throw"); } catch (TimeoutException&) @@ -220,7 +221,7 @@ void SocketTest::testNonBlocking() { EchoServer echoServer; StreamSocket ss; - ss.connect(SocketAddress("localhost", echoServer.port())); + ss.connect(SocketAddress("127.0.0.1", echoServer.port())); ss.setBlocking(false); Timespan timeout(1000000); @@ -244,7 +245,7 @@ void SocketTest::testAddress() serv.bind(SocketAddress()); serv.listen(); StreamSocket ss; - ss.connect(SocketAddress("localhost", serv.address().port())); + ss.connect(SocketAddress("127.0.0.1", serv.address().port())); StreamSocket css = serv.acceptConnection(); assert (css.peerAddress().host() == ss.address().host()); assert (css.peerAddress().port() == ss.address().port()); @@ -306,7 +307,7 @@ void SocketTest::testTimeout() { EchoServer echoServer; StreamSocket ss; - ss.connect(SocketAddress("localhost", echoServer.port())); + ss.connect(SocketAddress("127.0.0.1", echoServer.port())); Timespan timeout0 = ss.getReceiveTimeout(); Timespan timeout(250000); @@ -344,7 +345,7 @@ void SocketTest::testTimeout() void SocketTest::testBufferSize() { EchoServer echoServer; - SocketAddress sa("localhost", 1234); + SocketAddress sa("127.0.0.1", 1234); StreamSocket ss(sa.family()); int osz = ss.getSendBufferSize(); @@ -368,7 +369,7 @@ void SocketTest::testOptions() { EchoServer echoServer; StreamSocket ss; - ss.connect(SocketAddress("localhost", echoServer.port())); + ss.connect(SocketAddress("127.0.0.1", echoServer.port())); ss.setLinger(true, 20); bool f; @@ -402,7 +403,7 @@ void SocketTest::testSelect() EchoServer echoServer; StreamSocket ss; - ss.connect(SocketAddress("localhost", echoServer.port())); + ss.connect(SocketAddress("127.0.0.1", echoServer.port())); Socket::SocketList readList; Socket::SocketList writeList; @@ -439,8 +440,8 @@ void SocketTest::testSelect2() EchoServer echoServer1; EchoServer echoServer2; - StreamSocket ss1(SocketAddress("localhost", echoServer1.port())); - StreamSocket ss2(SocketAddress("localhost", echoServer2.port())); + StreamSocket ss1(SocketAddress("127.0.0.1", echoServer1.port())); + StreamSocket ss2(SocketAddress("127.0.0.1", echoServer2.port())); Socket::SocketList readList; Socket::SocketList writeList; @@ -499,6 +500,28 @@ void SocketTest::testSelect3() } +void SocketTest::testEchoUnixLocal() +{ +#if defined(POCO_OS_FAMILY_UNIX) + Poco::File socketFile("/tmp/SocketTest.sock"); + if (socketFile.exists()) socketFile.remove(); + SocketAddress localAddr(SocketAddress::UNIX_LOCAL, socketFile.path()); + EchoServer echoServer(localAddr); + StreamSocket ss(SocketAddress::UNIX_LOCAL); + ss.connect(localAddr); + int n = ss.sendBytes("hello", 5); + assert (n == 5); + char buffer[256]; + n = ss.receiveBytes(buffer, sizeof(buffer)); + assert (n == 5); + assert (std::string(buffer, n) == "hello"); + ss.close(); + socketFile.remove(); +#endif +} + + + void SocketTest::onReadable(bool& b) { if (b) ++_notToReadable; @@ -547,6 +570,7 @@ CppUnit::Test* SocketTest::suite() CppUnit_addTest(pSuite, SocketTest, testSelect); CppUnit_addTest(pSuite, SocketTest, testSelect2); CppUnit_addTest(pSuite, SocketTest, testSelect3); + CppUnit_addTest(pSuite, SocketTest, testEchoUnixLocal); return pSuite; } diff --git a/Net/testsuite/src/SocketTest.h b/Net/testsuite/src/SocketTest.h index b48b87341..775b882d2 100644 --- a/Net/testsuite/src/SocketTest.h +++ b/Net/testsuite/src/SocketTest.h @@ -40,6 +40,7 @@ public: void testSelect(); void testSelect2(); void testSelect3(); + void testEchoUnixLocal(); void setUp(); void tearDown(); diff --git a/Net/testsuite/src/SyslogTest.cpp b/Net/testsuite/src/SyslogTest.cpp index b1aaff2ee..081b2f082 100644 --- a/Net/testsuite/src/SyslogTest.cpp +++ b/Net/testsuite/src/SyslogTest.cpp @@ -123,7 +123,7 @@ SyslogTest::~SyslogTest() void SyslogTest::testListener() { Poco::AutoPtr channel = new RemoteSyslogChannel(); - channel->setProperty("loghost", "localhost:51400"); + channel->setProperty("loghost", "127.0.0.1:51400"); channel->open(); Poco::AutoPtr listener = new RemoteSyslogListener(51400); listener->open(); @@ -148,7 +148,7 @@ void SyslogTest::testListener() void SyslogTest::testChannelOpenClose() { Poco::AutoPtr channel = new RemoteSyslogChannel(); - channel->setProperty("loghost", "localhost:51400"); + channel->setProperty("loghost", "127.0.0.1:51400"); channel->open(); Poco::AutoPtr listener = new RemoteSyslogListener(51400); listener->open(); @@ -187,7 +187,7 @@ void SyslogTest::testChannelOpenClose() void SyslogTest::testOldBSD() { Poco::AutoPtr channel = new RemoteSyslogChannel(); - channel->setProperty("loghost", "localhost:51400"); + channel->setProperty("loghost", "127.0.0.1:51400"); channel->setProperty("format", "bsd"); channel->open(); Poco::AutoPtr listener = new RemoteSyslogListener(51400); diff --git a/Net/testsuite/src/TCPServerTest.cpp b/Net/testsuite/src/TCPServerTest.cpp index 55d63e861..59fa83cc7 100644 --- a/Net/testsuite/src/TCPServerTest.cpp +++ b/Net/testsuite/src/TCPServerTest.cpp @@ -22,6 +22,7 @@ using Poco::Net::TCPServer; +using Poco::Net::TCPServerConnectionFilter; using Poco::Net::TCPServerConnection; using Poco::Net::TCPServerConnectionFactory; using Poco::Net::TCPServerConnectionFactoryImpl; @@ -60,6 +61,15 @@ namespace } } }; + + class RejectFilter: public TCPServerConnectionFilter + { + public: + bool accept(const StreamSocket&) + { + return false; + } + }; } @@ -82,7 +92,7 @@ void TCPServerTest::testOneConnection() assert (srv.queuedConnections() == 0); assert (srv.totalConnections() == 0); - SocketAddress sa("localhost", srv.socket().address().port()); + SocketAddress sa("127.0.0.1", srv.socket().address().port()); StreamSocket ss1(sa); std::string data("hello, world"); ss1.sendBytes(data.data(), (int) data.size()); @@ -109,7 +119,7 @@ void TCPServerTest::testTwoConnections() assert (srv.queuedConnections() == 0); assert (srv.totalConnections() == 0); - SocketAddress sa("localhost", srv.socket().address().port()); + SocketAddress sa("127.0.0.1", srv.socket().address().port()); StreamSocket ss1(sa); StreamSocket ss2(sa); std::string data("hello, world"); @@ -157,7 +167,7 @@ void TCPServerTest::testMultiConnections() assert (srv.queuedConnections() == 0); assert (srv.totalConnections() == 0); - SocketAddress sa("localhost", svs.address().port()); + SocketAddress sa("127.0.0.1", svs.address().port()); StreamSocket ss1(sa); StreamSocket ss2(sa); StreamSocket ss3(sa); @@ -231,7 +241,9 @@ void TCPServerTest::testMultiConnections() assert (srv.currentConnections() == 0); } -void TCPServerTest::testThreadCapacity(){ + +void TCPServerTest::testThreadCapacity() +{ ServerSocket svs(0); TCPServerParams* pParams = new TCPServerParams; pParams->setMaxThreads(64); @@ -241,6 +253,29 @@ void TCPServerTest::testThreadCapacity(){ } +void TCPServerTest::testFilter() +{ + TCPServer srv(new TCPServerConnectionFactoryImpl()); + srv.setConnectionFilter(new RejectFilter); + srv.start(); + assert (srv.currentConnections() == 0); + assert (srv.currentThreads() == 0); + assert (srv.queuedConnections() == 0); + assert (srv.totalConnections() == 0); + + SocketAddress sa("127.0.0.1", srv.socket().address().port()); + StreamSocket ss(sa); + + char buffer[256]; + int n = ss.receiveBytes(buffer, sizeof(buffer)); + + assert (n == 0); + assert (srv.currentConnections() == 0); + assert (srv.currentThreads() == 0); + assert (srv.queuedConnections() == 0); + assert (srv.totalConnections() == 0); +} + void TCPServerTest::setUp() { @@ -260,6 +295,7 @@ CppUnit::Test* TCPServerTest::suite() CppUnit_addTest(pSuite, TCPServerTest, testTwoConnections); CppUnit_addTest(pSuite, TCPServerTest, testMultiConnections); CppUnit_addTest(pSuite, TCPServerTest, testThreadCapacity); + CppUnit_addTest(pSuite, TCPServerTest, testFilter); return pSuite; } diff --git a/Net/testsuite/src/TCPServerTest.h b/Net/testsuite/src/TCPServerTest.h index 527b656c0..6a332e401 100644 --- a/Net/testsuite/src/TCPServerTest.h +++ b/Net/testsuite/src/TCPServerTest.h @@ -28,6 +28,7 @@ public: void testTwoConnections(); void testMultiConnections(); void testThreadCapacity(); + void testFilter(); void setUp(); void tearDown(); diff --git a/Net/testsuite/src/WebSocketTest.cpp b/Net/testsuite/src/WebSocketTest.cpp index 09ccd6aee..b832d8d1b 100644 --- a/Net/testsuite/src/WebSocketTest.cpp +++ b/Net/testsuite/src/WebSocketTest.cpp @@ -118,7 +118,7 @@ void WebSocketTest::testWebSocket() Poco::Thread::sleep(200); - HTTPClientSession cs("localhost", ss.address().port()); + HTTPClientSession cs("127.0.0.1", ss.address().port()); HTTPRequest request(HTTPRequest::HTTP_GET, "/ws", HTTPRequest::HTTP_1_1); HTTPResponse response; WebSocket ws(cs, request, response); @@ -140,6 +140,13 @@ void WebSocketTest::testWebSocket() assert (n == payload.size()); assert (payload.compare(0, payload.size(), buffer, 0, n) == 0); assert (flags == WebSocket::FRAME_TEXT); + + ws.sendFrame(payload.data(), (int) payload.size()); + Poco::Buffer pocobuffer(0); + n = ws.receiveFrame(pocobuffer, flags); + assert (n == payload.size()); + assert (payload.compare(0, payload.size(), pocobuffer.begin(), 0, n) == 0); + assert (flags == WebSocket::FRAME_TEXT); } for (int i = 125; i < 129; i++) @@ -150,6 +157,13 @@ void WebSocketTest::testWebSocket() assert (n == payload.size()); assert (payload.compare(0, payload.size(), buffer, 0, n) == 0); assert (flags == WebSocket::FRAME_TEXT); + + ws.sendFrame(payload.data(), (int) payload.size()); + Poco::Buffer pocobuffer(0); + n = ws.receiveFrame(pocobuffer, flags); + assert (n == payload.size()); + assert (payload.compare(0, payload.size(), pocobuffer.begin(), 0, n) == 0); + assert (flags == WebSocket::FRAME_TEXT); } payload = "Hello, world!"; @@ -185,7 +199,7 @@ void WebSocketTest::testWebSocketLarge() Poco::Thread::sleep(200); - HTTPClientSession cs("localhost", ss.address().port()); + HTTPClientSession cs("127.0.0.1", ss.address().port()); HTTPRequest request(HTTPRequest::HTTP_GET, "/ws", HTTPRequest::HTTP_1_1); HTTPResponse response; WebSocket ws(cs, request, response); @@ -209,6 +223,49 @@ void WebSocketTest::testWebSocketLarge() } +void WebSocketTest::testOneLargeFrame(int msgSize) +{ + Poco::Net::ServerSocket ss(0); + Poco::Net::HTTPServer server(new WebSocketRequestHandlerFactory(msgSize), ss, new Poco::Net::HTTPServerParams); + server.start(); + + Poco::Thread::sleep(200); + + HTTPClientSession cs("127.0.0.1", ss.address().port()); + HTTPRequest request(HTTPRequest::HTTP_GET, "/ws", HTTPRequest::HTTP_1_1); + HTTPResponse response; + WebSocket ws(cs, request, response); + ws.setSendBufferSize(msgSize); + ws.setReceiveBufferSize(msgSize); + std::string payload(msgSize, 'x'); + + ws.sendFrame(payload.data(), msgSize); + + Poco::Buffer buffer(msgSize); + int flags; + int n; + + n = ws.receiveFrame(buffer.begin(), buffer.size(), flags); + assert (n == payload.size()); + assert (payload.compare(0, payload.size(), buffer.begin(), 0, n) == 0); + + ws.sendFrame(payload.data(), msgSize); + + Poco::Buffer pocobuffer(0); + + n = ws.receiveFrame(pocobuffer, flags); + assert (n == payload.size()); + assert (payload.compare(0, payload.size(), pocobuffer.begin(), 0, n) == 0); +} + + +void WebSocketTest::testWebSocketLargeInOneFrame() +{ + testOneLargeFrame(64000); + testOneLargeFrame(70000); +} + + void WebSocketTest::setUp() { } @@ -225,6 +282,7 @@ CppUnit::Test* WebSocketTest::suite() CppUnit_addTest(pSuite, WebSocketTest, testWebSocket); CppUnit_addTest(pSuite, WebSocketTest, testWebSocketLarge); + CppUnit_addTest(pSuite, WebSocketTest, testWebSocketLargeInOneFrame); return pSuite; } diff --git a/Net/testsuite/src/WebSocketTest.h b/Net/testsuite/src/WebSocketTest.h index 87d943da7..a32a26633 100644 --- a/Net/testsuite/src/WebSocketTest.h +++ b/Net/testsuite/src/WebSocketTest.h @@ -26,6 +26,7 @@ public: void testWebSocket(); void testWebSocketLarge(); + void testWebSocketLargeInOneFrame(); void setUp(); void tearDown(); @@ -33,6 +34,7 @@ public: static CppUnit::Test* suite(); private: + void testOneLargeFrame(int msgSize); };