Browse Source

porting rev.1894 to trunk

Aleksandar Fabijanic 13 years ago
parent
commit
03ddca58f5

+ 6 - 2
CHANGELOG

@@ -1,7 +1,7 @@
 This is the changelog file for the POCO C++ Libraries.
 
 
-Release 1.5.0 (2012-07-30)
+Release 1.5.0 (2012-08-??)
 ==========================
 
 - added JSON
@@ -23,7 +23,7 @@ Release 1.5.0 (2012-07-30)
 - IPAddress force IPv6 always lowercase (RFC 5952)
 - fixed SF#3538785: SMTPClientSession::sendMessage() should take recipient list 
 
-Release 1.4.4 (2012-07-??)
+Release 1.4.4 (2012-08-??)
 ==========================
 
 - ZipStream now builds correctly in unbundled build.
@@ -53,6 +53,10 @@ Release 1.4.4 (2012-07-??)
 - Added Poco::ObjectPool class template.
 - Poco::Net::HTTPServer has a new stopAll() method allowing stopping/aborting of all
   currently active client connections.
+- The HTTP server framework now actively prevents sending a message body in the
+  response to a HEAD request, or in case of a 204 No Content or 304 Not Modified
+  response status.
+- fixed a DOM parser performance bug (patch by Peter Klotz)
 
 Release 1.4.3p1 (2012-01-23)
 ============================

+ 12 - 6
Net/include/Poco/Net/HTTPFixedLengthStream.h

@@ -63,7 +63,13 @@ class Net_API HTTPFixedLengthStreamBuf: public HTTPBasicStreamBuf
 public:
 	typedef HTTPBasicStreamBuf::openmode openmode;
 
-	HTTPFixedLengthStreamBuf(HTTPSession& session, std::streamsize length, openmode mode);
+#if defined(POCO_HAVE_INT64)
+	typedef Poco::Int64 ContentLength;
+#else
+	typedef std::streamsize ContentLength;
+#endif
+
+	HTTPFixedLengthStreamBuf(HTTPSession& session, ContentLength length, openmode mode);
 	~HTTPFixedLengthStreamBuf();
 	
 protected:
@@ -72,8 +78,8 @@ protected:
 
 private:
 	HTTPSession&    _session;
-	std::streamsize _length;
-	std::streamsize _count;
+	ContentLength _length;
+	ContentLength _count;
 };
 
 
@@ -81,7 +87,7 @@ class Net_API HTTPFixedLengthIOS: public virtual std::ios
 	/// The base class for HTTPFixedLengthInputStream.
 {
 public:
-	HTTPFixedLengthIOS(HTTPSession& session, std::streamsize length, HTTPFixedLengthStreamBuf::openmode mode);
+	HTTPFixedLengthIOS(HTTPSession& session, HTTPFixedLengthStreamBuf::ContentLength length, HTTPFixedLengthStreamBuf::openmode mode);
 	~HTTPFixedLengthIOS();
 	HTTPFixedLengthStreamBuf* rdbuf();
 
@@ -94,7 +100,7 @@ class Net_API HTTPFixedLengthInputStream: public HTTPFixedLengthIOS, public std:
 	/// This class is for internal use by HTTPSession only.
 {
 public:
-	HTTPFixedLengthInputStream(HTTPSession& session, std::streamsize length);
+	HTTPFixedLengthInputStream(HTTPSession& session, HTTPFixedLengthStreamBuf::ContentLength length);
 	~HTTPFixedLengthInputStream();
 	
 	void* operator new(std::size_t size);
@@ -109,7 +115,7 @@ class Net_API HTTPFixedLengthOutputStream: public HTTPFixedLengthIOS, public std
 	/// This class is for internal use by HTTPSession only.
 {
 public:
-	HTTPFixedLengthOutputStream(HTTPSession& session, std::streamsize length);
+	HTTPFixedLengthOutputStream(HTTPSession& session, HTTPFixedLengthStreamBuf::ContentLength length);
 	~HTTPFixedLengthOutputStream();
 
 	void* operator new(std::size_t size);

+ 9 - 0
Net/include/Poco/Net/HTTPMessage.h

@@ -95,6 +95,9 @@ public:
 		/// always returns a 64-bit integer for content length.
 #endif // defined(POCO_HAVE_INT64)
 
+	bool hasContentLength() const;
+		/// Returns true iff a Content-Length header is present.
+
 	void setTransferEncoding(const std::string& transferEncoding);
 		/// Sets the transfer encoding for this message.
 		///
@@ -192,6 +195,12 @@ inline const std::string& HTTPMessage::getVersion() const
 }
 
 
+inline bool HTTPMessage::hasContentLength() const
+{
+	return has(CONTENT_LENGTH);
+}
+
+
 } } // namespace Poco::Net
 
 

+ 3 - 2
Net/include/Poco/Net/HTTPServerRequestImpl.h

@@ -42,6 +42,7 @@
 
 #include "Poco/Net/Net.h"
 #include "Poco/Net/HTTPServerRequest.h"
+#include "Poco/Net/HTTPServerResponseImpl.h"
 #include "Poco/Net/SocketAddress.h"
 #include "Poco/AutoPtr.h"
 #include <istream>
@@ -64,7 +65,7 @@ class Net_API HTTPServerRequestImpl: public HTTPServerRequest
 	/// handleRequest() method of HTTPRequestHandler.
 {
 public:
-	HTTPServerRequestImpl(HTTPServerResponse& response, HTTPServerSession& session, HTTPServerParams* pParams);
+	HTTPServerRequestImpl(HTTPServerResponseImpl& response, HTTPServerSession& session, HTTPServerParams* pParams);
 		/// Creates the HTTPServerRequestImpl, using the
 		/// given HTTPServerSession.
 
@@ -105,7 +106,7 @@ protected:
 	static const std::string EXPECT;
 	
 private:
-	HTTPServerResponse&             _response;
+	HTTPServerResponseImpl&         _response;
 	HTTPServerSession&              _session;
 	std::istream*                   _pStream;
 	Poco::AutoPtr<HTTPServerParams> _pParams;

+ 13 - 1
Net/include/Poco/Net/HTTPServerResponseImpl.h

@@ -49,7 +49,7 @@ namespace Net {
 
 
 class HTTPServerSession;
-class HTTPCookie;
+class HTTPServerRequestImpl;
 
 
 class Net_API HTTPServerResponseImpl: public HTTPServerResponse
@@ -128,9 +128,15 @@ public:
 	bool sent() const;
 		/// Returns true if the response (header) has been sent.
 
+protected:
+	void attachRequest(HTTPServerRequestImpl* pRequest);
+	
 private:
 	HTTPServerSession& _session;
+	HTTPServerRequestImpl* _pRequest;
 	std::ostream*      _pStream;
+	
+	friend class HTTPServerRequestImpl;
 };
 
 
@@ -143,6 +149,12 @@ inline bool HTTPServerResponseImpl::sent() const
 }
 
 
+inline void HTTPServerResponseImpl::attachRequest(HTTPServerRequestImpl* pRequest)
+{
+	_pRequest = pRequest;
+}
+
+
 } } // namespace Poco::Net
 
 

+ 11 - 3
Net/src/HTTPClientSession.cpp

@@ -223,11 +223,15 @@ std::ostream& HTTPClientSession::sendRequest(HTTPRequest& request)
 			request.write(hos);
 			_pRequestStream = new HTTPChunkedOutputStream(*this);
 		}
-		else if (request.getContentLength() != HTTPMessage::UNKNOWN_CONTENT_LENGTH)
+		else if (request.hasContentLength())
 		{
 			Poco::CountingOutputStream cs;
 			request.write(cs);
+#if POCO_HAVE_INT64
+			_pRequestStream = new HTTPFixedLengthOutputStream(*this, request.getContentLength64() + cs.chars());
+#else
 			_pRequestStream = new HTTPFixedLengthOutputStream(*this, request.getContentLength() + cs.chars());
+#endif
 			request.write(*_pRequestStream);
 		}
 		else if (request.getMethod() != HTTPRequest::HTTP_PUT && request.getMethod() != HTTPRequest::HTTP_POST)
@@ -284,12 +288,16 @@ std::istream& HTTPClientSession::receiveResponse(HTTPResponse& response)
 
 	_mustReconnect = getKeepAlive() && !response.getKeepAlive();
 
-	if (!_expectResponseBody)
+	if (!_expectResponseBody || response.getStatus() < 200 || response.getStatus() == HTTPResponse::HTTP_NO_CONTENT || response.getStatus() == HTTPResponse::HTTP_NOT_MODIFIED)
 		_pResponseStream = new HTTPFixedLengthInputStream(*this, 0);
 	else if (response.getChunkedTransferEncoding())
 		_pResponseStream = new HTTPChunkedInputStream(*this);
-	else if (response.getContentLength() != HTTPMessage::UNKNOWN_CONTENT_LENGTH)
+	else if (response.hasContentLength())
+#if defined(POCO_HAVE_INT64)
+		_pResponseStream = new HTTPFixedLengthInputStream(*this, response.getContentLength64());
+#else
 		_pResponseStream = new HTTPFixedLengthInputStream(*this, response.getContentLength());
+#endif
 	else
 		_pResponseStream = new HTTPInputStream(*this);
 		

+ 6 - 6
Net/src/HTTPFixedLengthStream.cpp

@@ -50,7 +50,7 @@ namespace Net {
 //
 
 
-HTTPFixedLengthStreamBuf::HTTPFixedLengthStreamBuf(HTTPSession& session, std::streamsize length, openmode mode):
+HTTPFixedLengthStreamBuf::HTTPFixedLengthStreamBuf(HTTPSession& session, ContentLength length, openmode mode):
 	HTTPBasicStreamBuf(HTTPBufferAllocator::BUFFER_SIZE, mode),
 	_session(session),
 	_length(length),
@@ -70,7 +70,7 @@ int HTTPFixedLengthStreamBuf::readFromDevice(char* buffer, std::streamsize lengt
 	if (_count < _length)
 	{
 		if (_count + length > _length)
-			length = _length - _count;
+			length = static_cast<std::streamsize>(_length - _count);
 		n = _session.read(buffer, length);
 		if (n > 0) _count += n;
 	}
@@ -84,7 +84,7 @@ int HTTPFixedLengthStreamBuf::writeToDevice(const char* buffer, std::streamsize
 	if (_count < _length)
 	{
 		if (_count + length > _length)
-			length = _length - _count;
+			length = static_cast<std::streamsize>(_length - _count);
 		n = _session.write(buffer, length);
 		if (n > 0) _count += n;
 	}
@@ -97,7 +97,7 @@ int HTTPFixedLengthStreamBuf::writeToDevice(const char* buffer, std::streamsize
 //
 
 
-HTTPFixedLengthIOS::HTTPFixedLengthIOS(HTTPSession& session, std::streamsize length, HTTPFixedLengthStreamBuf::openmode mode):
+HTTPFixedLengthIOS::HTTPFixedLengthIOS(HTTPSession& session, HTTPFixedLengthStreamBuf::ContentLength length, HTTPFixedLengthStreamBuf::openmode mode):
 	_buf(session, length, mode)
 {
 	poco_ios_init(&_buf);
@@ -130,7 +130,7 @@ HTTPFixedLengthStreamBuf* HTTPFixedLengthIOS::rdbuf()
 Poco::MemoryPool HTTPFixedLengthInputStream::_pool(sizeof(HTTPFixedLengthInputStream));
 
 
-HTTPFixedLengthInputStream::HTTPFixedLengthInputStream(HTTPSession& session, std::streamsize length):
+HTTPFixedLengthInputStream::HTTPFixedLengthInputStream(HTTPSession& session, HTTPFixedLengthStreamBuf::ContentLength length):
 	HTTPFixedLengthIOS(session, length, std::ios::in),
 	std::istream(&_buf)
 {
@@ -162,7 +162,7 @@ void HTTPFixedLengthInputStream::operator delete(void* ptr)
 Poco::MemoryPool HTTPFixedLengthOutputStream::_pool(sizeof(HTTPFixedLengthOutputStream));
 
 
-HTTPFixedLengthOutputStream::HTTPFixedLengthOutputStream(HTTPSession& session, std::streamsize length):
+HTTPFixedLengthOutputStream::HTTPFixedLengthOutputStream(HTTPSession& session, HTTPFixedLengthStreamBuf::ContentLength length):
 	HTTPFixedLengthIOS(session, length, std::ios::out),
 	std::ostream(&_buf)
 {

+ 20 - 1
Net/src/HTTPServerConnection.cpp

@@ -105,7 +105,15 @@ void HTTPServerConnection::run()
 				catch (Poco::Exception&)
 				{
 					if (!response.sent())
-						sendErrorResponse(session, HTTPResponse::HTTP_INTERNAL_SERVER_ERROR);
+					{
+						try
+						{
+							sendErrorResponse(session, HTTPResponse::HTTP_INTERNAL_SERVER_ERROR);
+						}
+						catch (...)
+						{
+						}
+					}
 					throw;
 				}
 			}
@@ -140,7 +148,14 @@ void HTTPServerConnection::onServerStopped(const bool& abortCurrent)
 	{
 		try
 		{
+			// Note: On Windows, select() will not return if one of its socket is being
+			// shut down. Therefore we have to call close(), which works better.
+			// On other platforms, we do the more graceful thing.
+#if defined(_WIN32)
 			socket().close();
+#else
+			socket().shutdown();
+#endif
 		}
 		catch (...)
 		{
@@ -152,7 +167,11 @@ void HTTPServerConnection::onServerStopped(const bool& abortCurrent)
 
 		try
 		{
+#if defined(_WIN32)
 			socket().close();
+#else
+			socket().shutdown();
+#endif
 		}
 		catch (...)
 		{

+ 9 - 2
Net/src/HTTPServerRequestImpl.cpp

@@ -35,6 +35,7 @@
 
 
 #include "Poco/Net/HTTPServerRequestImpl.h"
+#include "Poco/Net/HTTPServerResponseImpl.h"
 #include "Poco/Net/HTTPServerSession.h"
 #include "Poco/Net/HTTPHeaderStream.h"
 #include "Poco/Net/HTTPStream.h"
@@ -54,12 +55,14 @@ namespace Net {
 const std::string HTTPServerRequestImpl::EXPECT("Expect");
 
 
-HTTPServerRequestImpl::HTTPServerRequestImpl(HTTPServerResponse& response, HTTPServerSession& session, HTTPServerParams* pParams):
+HTTPServerRequestImpl::HTTPServerRequestImpl(HTTPServerResponseImpl& response, HTTPServerSession& session, HTTPServerParams* pParams):
 	_response(response),
 	_session(session),
 	_pStream(0),
 	_pParams(pParams, true)
 {
+	response.attachRequest(this);
+
 	HTTPHeaderInputStream hs(session);
 	read(hs);
 	
@@ -69,8 +72,12 @@ HTTPServerRequestImpl::HTTPServerRequestImpl(HTTPServerResponse& response, HTTPS
 	
 	if (getChunkedTransferEncoding())
 		_pStream = new HTTPChunkedInputStream(session);
-	else if (getContentLength() != HTTPMessage::UNKNOWN_CONTENT_LENGTH)
+	else if (hasContentLength())
+#if defined(POCO_HAVE_INT64)
+		_pStream = new HTTPFixedLengthInputStream(session, getContentLength64());
+#else
 		_pStream = new HTTPFixedLengthInputStream(session, getContentLength());
+#endif
 	else if (getMethod() == HTTPRequest::HTTP_GET || getMethod() == HTTPRequest::HTTP_HEAD)
 		_pStream = new HTTPFixedLengthInputStream(session, 0);
 	else

+ 26 - 4
Net/src/HTTPServerResponseImpl.cpp

@@ -35,6 +35,7 @@
 
 
 #include "Poco/Net/HTTPServerResponseImpl.h"
+#include "Poco/Net/HTTPServerRequestImpl.h"
 #include "Poco/Net/HTTPServerSession.h"
 #include "Poco/Net/HTTPHeaderStream.h"
 #include "Poco/Net/HTTPStream.h"
@@ -66,6 +67,7 @@ namespace Net {
 
 HTTPServerResponseImpl::HTTPServerResponseImpl(HTTPServerSession& session):
 	_session(session),
+	_pRequest(0),
 	_pStream(0)
 {
 }
@@ -88,17 +90,31 @@ std::ostream& HTTPServerResponseImpl::send()
 {
 	poco_assert (!_pStream);
 
-	if (getChunkedTransferEncoding())
+	if (_pRequest && _pRequest->getMethod() == HTTPRequest::HTTP_HEAD ||
+		getStatus() < 200 ||
+		getStatus() == HTTPResponse::HTTP_NO_CONTENT ||
+		getStatus() == HTTPResponse::HTTP_NOT_MODIFIED)
+	{
+		Poco::CountingOutputStream cs;
+		write(cs);
+		_pStream = new HTTPFixedLengthOutputStream(_session, cs.chars());
+		write(*_pStream);
+	}
+	else if (getChunkedTransferEncoding())
 	{
 		HTTPHeaderOutputStream hs(_session);
 		write(hs);
 		_pStream = new HTTPChunkedOutputStream(_session);
 	}
-	else if (getContentLength() != HTTPMessage::UNKNOWN_CONTENT_LENGTH)
+	else if (hasContentLength())
 	{
 		Poco::CountingOutputStream cs;
 		write(cs);
+#if defined(POCO_HAVE_INT64)	
+		_pStream = new HTTPFixedLengthOutputStream(_session, getContentLength64() + cs.chars());
+#else
 		_pStream = new HTTPFixedLengthOutputStream(_session, getContentLength() + cs.chars());
+#endif
 		write(*_pStream);
 	}
 	else
@@ -132,7 +148,10 @@ void HTTPServerResponseImpl::sendFile(const std::string& path, const std::string
 	{
 		_pStream = new HTTPHeaderOutputStream(_session);
 		write(*_pStream);
-		StreamCopier::copyStream(istr, *_pStream);
+		if (_pRequest && _pRequest->getMethod() != HTTPRequest::HTTP_HEAD)
+		{
+			StreamCopier::copyStream(istr, *_pStream);
+		}
 	}
 	else throw OpenFileException(path);
 }
@@ -147,7 +166,10 @@ void HTTPServerResponseImpl::sendBuffer(const void* pBuffer, std::size_t length)
 	
 	_pStream = new HTTPHeaderOutputStream(_session);
 	write(*_pStream);
-	_pStream->write(static_cast<const char*>(pBuffer), static_cast<std::streamsize>(length));
+	if (_pRequest && _pRequest->getMethod() != HTTPRequest::HTTP_HEAD)
+	{
+		_pStream->write(static_cast<const char*>(pBuffer), static_cast<std::streamsize>(length));
+	}
 }
 
 

+ 4 - 3
Net/src/SocketImpl.cpp

@@ -523,6 +523,7 @@ bool SocketImpl::poll(const Poco::Timespan& timeout, int mode)
 		FD_SET(sockfd, &fdExcept);
 	}
 	Poco::Timespan remainingTime(timeout);
+	int errorCode;
 	int rc;
 	do
 	{
@@ -531,7 +532,7 @@ bool SocketImpl::poll(const Poco::Timespan& timeout, int mode)
 		tv.tv_usec = (long) remainingTime.useconds();
 		Poco::Timestamp start;
 		rc = ::select(int(sockfd) + 1, &fdRead, &fdWrite, &fdExcept, &tv);
-		if (rc < 0 && lastError() == POCO_EINTR)
+		if (rc < 0 && (errorCode = lastError()) == POCO_EINTR)
 		{
 			Poco::Timestamp end;
 			Poco::Timespan waited = end - start;
@@ -541,8 +542,8 @@ bool SocketImpl::poll(const Poco::Timespan& timeout, int mode)
 				remainingTime = 0;
 		}
 	}
-	while (rc < 0 && lastError() == POCO_EINTR);
-	if (rc < 0) error();
+	while (rc < 0 && errorCode == POCO_EINTR);
+	if (rc < 0) error(errorCode);
 	return rc > 0; 
 
 #endif // POCO_HAVE_FD_EPOLL

+ 1 - 1
PageCompiler/samples/HTTPTimeServer/Makefile

@@ -9,7 +9,7 @@
 include $(POCO_BASE)/build/rules/global
 
 # Where to find the PageCompiler executable
-PAGECOMPILER = $(POCO_BASE)/PageCompiler/bin/$(POCO_HOST_OSNAME)/$(POCO_HOST_OSARCH)/cpspc$(OSARCH_POSTFIX)
+PAGECOMPILER = $(POCO_BASE)/PageCompiler/bin/$(POCO_HOST_OSNAME)/$(POCO_HOST_OSARCH)/cpspc
 
 objects = HTTPTimeServerApp TimeHandler
 

+ 48 - 15
XML/src/CharacterData.cpp

@@ -64,9 +64,16 @@ CharacterData::~CharacterData()
 
 void CharacterData::setData(const XMLString& data)
 {
-	XMLString oldData = getData();
-	_data = data;
-	if (events()) dispatchCharacterDataModified(oldData, _data);
+	if (events())
+	{
+		XMLString oldData = _data;
+		_data = data;
+		dispatchCharacterDataModified(oldData, _data);
+	}
+	else
+	{
+		_data = data;
+	}
 }
 
 
@@ -81,9 +88,16 @@ XMLString CharacterData::substringData(unsigned long offset, unsigned long count
 
 void CharacterData::appendData(const XMLString& arg)
 {
-	XMLString oldData = _data;
-	_data.append(arg);
-	if (events()) dispatchCharacterDataModified(oldData, _data);
+	if (events())
+	{
+		XMLString oldData = _data;
+		_data.append(arg);
+		dispatchCharacterDataModified(oldData, _data);
+	}
+	else
+	{
+		_data.append(arg);
+	}
 }
 
 
@@ -92,9 +106,16 @@ void CharacterData::insertData(unsigned long offset, const XMLString& arg)
 	if (offset > _data.length())
 		throw DOMException(DOMException::INDEX_SIZE_ERR);
 
-	XMLString oldData = _data;
-	_data.insert(offset, arg);
-	if (events()) dispatchCharacterDataModified(oldData, _data);
+	if (events())
+	{
+		XMLString oldData = _data;
+		_data.insert(offset, arg);
+		dispatchCharacterDataModified(oldData, _data);
+	}
+	else
+	{
+		_data.insert(offset, arg);
+	}
 }
 
 
@@ -103,9 +124,14 @@ void CharacterData::deleteData(unsigned long offset, unsigned long count)
 	if (offset >= _data.length())
 		throw DOMException(DOMException::INDEX_SIZE_ERR);
 
-	XMLString oldData = _data;
-	_data.replace(offset, count, EMPTY_STRING);
-	if (events()) dispatchCharacterDataModified(oldData, _data);
+	if (events())
+	{
+		XMLString oldData = _data;
+		_data.replace(offset, count, EMPTY_STRING);
+		dispatchCharacterDataModified(oldData, _data);
+	}
+	else
+		_data.replace(offset, count, EMPTY_STRING);
 }
 
 
@@ -114,9 +140,16 @@ void CharacterData::replaceData(unsigned long offset, unsigned long count, const
 	if (offset >= _data.length())
 		throw DOMException(DOMException::INDEX_SIZE_ERR);
 
-	XMLString oldData = _data;
-	_data.replace(offset, count, arg);
-	if (events()) dispatchCharacterDataModified(oldData, _data);
+	if (events())
+	{
+		XMLString oldData = _data;
+		_data.replace(offset, count, arg);
+		dispatchCharacterDataModified(oldData, _data);
+	}
+	else
+	{
+		_data.replace(offset, count, arg);
+	}
 }