📄 httpconnection.cpp
字号:
//%2006//////////////////////////////////////////////////////////////////////////// Copyright (c) 2000, 2001, 2002 BMC Software; Hewlett-Packard Development// Company, L.P.; IBM Corp.; The Open Group; Tivoli Systems.// Copyright (c) 2003 BMC Software; Hewlett-Packard Development Company, L.P.;// IBM Corp.; EMC Corporation, The Open Group.// Copyright (c) 2004 BMC Software; Hewlett-Packard Development Company, L.P.;// IBM Corp.; EMC Corporation; VERITAS Software Corporation; The Open Group.// Copyright (c) 2005 Hewlett-Packard Development Company, L.P.; IBM Corp.;// EMC Corporation; VERITAS Software Corporation; The Open Group.// Copyright (c) 2006 Hewlett-Packard Development Company, L.P.; IBM Corp.;// EMC Corporation; Symantec Corporation; The Open Group.//// Permission is hereby granted, free of charge, to any person obtaining a copy// of this software and associated documentation files (the "Software"), to// deal in the Software without restriction, including without limitation the// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or// sell copies of the Software, and to permit persons to whom the Software is// furnished to do so, subject to the following conditions:// // THE ABOVE COPYRIGHT NOTICE AND THIS PERMISSION NOTICE SHALL BE INCLUDED IN// ALL COPIES OR SUBSTANTIAL PORTIONS OF THE SOFTWARE. THE SOFTWARE IS PROVIDED// "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT// LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.////==============================================================================////%/////////////////////////////////////////////////////////////////////////////#include <Pegasus/Common/Config.h>#include <Pegasus/Common/Constants.h>#include "Network.h"#include <iostream>#include <cctype>#include <cstdlib>#include "Signal.h"#include "Socket.h"#include "TLS.h"#include "HTTPConnection.h"#include "MessageQueue.h"#include "Monitor.h"#include "HTTPMessage.h"#include "Tracer.h"#include "Buffer.h"#include "LanguageParser.h"#ifdef PEGASUS_KERBEROS_AUTHENTICATION#include <Pegasus/Common/CIMKerberosSecurityAssociation.h>#endif#include <Pegasus/Common/XmlWriter.h>PEGASUS_USING_STD;PEGASUS_NAMESPACE_BEGIN// initialize the request countAtomicInt HTTPConnection::_requestCount(0);//////////////////////////////////////////////////////////////////////////////////// Local routines:///////////////////////////////////////////////////////////////////////////////////* * string and number constants for HTTP sending/receiving */// buffer size for sending receivingstatic const Uint32 httpTcpBufferSize = 8192;// string constants for HTTP header. "Name" represents strings on the left// side of headerNameTerminator and "Value" represents strings on the right// side of headerNameTerminator#define headerNameTrailer "Trailer"#undef CRLF#define CRLF "\r\n"static const char headerNameTransferTE[] = "TE";static const char headerNameTransferEncoding[] = "transfer-encoding";static const char headerNameContentLength[] = "content-length";static const char headerValueTransferEncodingChunked[] = "chunked";static const char headerValueTransferEncodingIdentity[] = "identity";static const char headerValueTEchunked[] = "chunked";static const char headerValueTEtrailers[] = "trailers";static const char headerNameError[] = "CIMError";static const char headerNameCode[] = "CIMStatusCode";static const char headerNameDescription[] = "CIMStatusCodeDescription";static const char headerNameOperation[] = "CIMOperation";static const char headerNameContentLanguage[] = "Content-Language";// the names comes from the HTTP specification on chunked transfer encodingstatic const char headerNameTerminator[] = ": ";static const char headerValueSeparator[] = ", ";static const char headerLineTerminator[] = CRLF;static const char headerTerminator[] = CRLF CRLF;static const char chunkLineTerminator[] = CRLF;static const char chunkTerminator[] = CRLF;static const char chunkBodyTerminator[] = CRLF;static const char trailerTerminator[] = CRLF;static const char chunkExtensionTerminator[] = ";";// string sizesstatic const Uint32 headerNameContentLengthLength = sizeof(headerNameContentLength) - 1;static const Uint32 headerValueTransferEncodingChunkedLength = sizeof(headerValueTransferEncodingChunked) - 1;static const Uint32 headerNameTransferEncodingLength = sizeof(headerNameTransferEncoding) - 1;static const Uint32 headerNameTerminatorLength =sizeof(headerNameTerminator)-1;static const Uint32 headerLineTerminatorLength =sizeof(headerLineTerminator)-1;static const Uint32 chunkLineTerminatorLength = sizeof(chunkLineTerminator)-1;static const Uint32 chunkTerminatorLength = sizeof(chunkTerminator)-1;static const Uint32 chunkBodyTerminatorLength = sizeof(chunkBodyTerminator)-1;static const Uint32 trailerTerminatorLength = sizeof(trailerTerminator)-1;static const Uint32 chunkExtensionTerminatorLength = sizeof(chunkExtensionTerminator) - 1;// the number of bytes it takes to place a Uint32 into a string (minus null)static const Uint32 numberAsStringLength = 10;/* * given an HTTP status code, return the description. not all codes are listed * here. Unmapped codes result in the internal error string. * Add any required future codes here. */static const String httpDetailDelimiter = headerValueSeparator;static const String httpStatusInternal = HTTP_STATUS_INTERNALSERVERERROR;/* * throw given http code with detail, file, line * This is shared client/server code. The caller will decide what to do * with the thrown message */static void _throwEventFailure(const String &status, const String &detail, const char *func, const char *file , Uint32 line){ String message = status + httpDetailDelimiter + detail; Tracer::trace(file, line, TRC_HTTP, Tracer::LEVEL2, message); if (status == httpStatusInternal) throw AssertionFailureException(file, line, message); else throw Exception(message);}// throw a http exception. This is used for both client and server common code.// The macro allows is used for file, line inclusion for debugging#define _throwEventFailure(status, detail) \ _throwEventFailure(status, String(detail), func, __FILE__, __LINE__)#define _socketWriteError() \ do \ { \ Tracer::trace(__FILE__, __LINE__, TRC_DISCARDED_DATA, Tracer::LEVEL2, \ "Socket write failed with error %d; could not write response " \ "to client. (Client may have timed out.)", \ getSocketError()); \ throw Exception("socket write error"); \ } \ while (0)static inline Uint32 _Min(Uint32 x, Uint32 y){ return x < y ? x : y;}static char* _FindSeparator(const char* data, Uint32 size){ const char* p = data; const char* end = p + size; while (p != end) { if (*p == '\r') { Uint32 n = end - p; if (n >= 2 && p[1] == '\n') return (char*)p; } else if (*p == '\n') return (char*)p; p++; } return 0;}// Used to test signal handlingvoid * sigabrt_generator(void * parm){ abort(); return 0;}//////////////////////////////////////////////////////////////////////////////////// HTTPConnection//////////////////////////////////////////////////////////////////////////////////HTTPConnection::HTTPConnection( Monitor* monitor, AutoPtr<MP_Socket>& socket, const String& ipAddress, MessageQueue* ownerMessageQueue, MessageQueue* outputMessageQueue) : Base(PEGASUS_QUEUENAME_HTTPCONNECTION), _monitor(monitor), _socket(socket), _ipAddress(ipAddress), _ownerMessageQueue(ownerMessageQueue), _outputMessageQueue(outputMessageQueue), _contentOffset(-1), _contentLength(-1), _connectionClosePending(false), _acceptPending(false){ PEG_METHOD_ENTER(TRC_HTTP, "HTTPConnection::HTTPConnection"); _socket->disableBlocking(); _authInfo.reset(new AuthenticationInfo(true)); // Add SSL verification information to the authentication information if (_socket->isSecure()) {#ifndef PEGASUS_PLATFORM_ZOS_ZSERIES_IBM if (_socket->isPeerVerificationEnabled() && _socket->isCertificateVerified()) { _authInfo->setAuthStatus(AuthenticationInfoRep::AUTHENTICATED); _authInfo->setAuthType(AuthenticationInfoRep::AUTH_TYPE_SSL); _authInfo->setClientCertificateChain( _socket->getPeerCertificateChain()); }#else if (_socket->isClientAuthenticated()) { _authInfo->setAuthStatus(AuthenticationInfoRep::AUTHENTICATED); _authInfo->setAuthenticatedUser(_socket->getAuthenticatedUser()); }#endif } _responsePending = false; _connectionRequestCount = 0; _transferEncodingChunkOffset = 0; PEG_TRACE_STRING(TRC_HTTP, Tracer::LEVEL2, "Connection IP address = " + _ipAddress); _authInfo->setIpAddress(_ipAddress); PEG_METHOD_EXIT();}HTTPConnection::~HTTPConnection(){ PEG_METHOD_ENTER(TRC_HTTP, "HTTPConnection::~HTTPConnection"); _socket->close(); PEG_METHOD_EXIT();}void HTTPConnection::enqueue(Message *message){ handleEnqueue(message);}void HTTPConnection::handleEnqueue(Message *message){ PEG_METHOD_ENTER(TRC_HTTP, "HTTPConnection::handleEnqueue"); if (! message) { PEG_METHOD_EXIT(); return; } AutoMutex connectionLock(_connection_mut); switch (message->getType()) { case SOCKET_MESSAGE: { Tracer::trace(TRC_HTTP, Tracer::LEVEL4, "HTTPConnection::handleEnqueue - SOCKET_MESSAGE"); SocketMessage* socketMessage = (SocketMessage*)message; if (socketMessage->events & SocketMessage::READ) _handleReadEvent(); break; } case HTTP_MESSAGE: { Tracer::trace(TRC_HTTP, Tracer::LEVEL4, "HTTPConnection::handleEnqueue - HTTP_MESSAGE"); _handleWriteEvent(*message); break; } default: // ATTN: need unexpected message error! break; } // switch delete message; PEG_METHOD_EXIT();}/* * handle the message coming down from the above. This is shared client and * server code. If the message is coming in chunks, then validate the chunk * sequence number. If the message is being processed on the server side, * make sure the client has requested transfer encodings and/or trailers before
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -