📄 httpconnection.cpp
字号:
_connectionClosePending = true; // NOTE: if there is a response pending while a close connection request // occurs, then this indicates potential activity on this connection apart // from this thread of execution (although this code here is locked, other // threads may be waiting on this one.) // The caller MUST check this value before attempting a delete of this // connnection, otherwise the delete may occur while other chunked responses // are waiting to be delivered through this connection. // This condition may happen on a client error/timeout/interrupt/disconnect if (_isClient() == false) { if (_responsePending == true) { Tracer::trace(TRC_DISCARDED_DATA, Tracer::LEVEL2, "HTTPConnection::_closeConnection - Close connection " "requested while responses are still expected on this " "connection. connection=0x%p, socket=%d\n", (void*)this, getSocket()); } // still set to DYING Tracer::trace(TRC_HTTP, Tracer::LEVEL2, "Now setting state to %d", _MonitorEntry::DYING); _monitor->setState (_entry_index, _MonitorEntry::DYING); _monitor->tickle(); } if (_connectionRequestCount == 0) { Tracer::trace(TRC_HTTP, Tracer::LEVEL4, "HTTPConnection::_closeConnection - Connection being closed " "without receiving any requests."); } PEG_METHOD_EXIT();// Message* message= new CloseConnectionMessage(_socket->getSocket));// message->dest = _ownerMessageQueue->getQueueId();// SendForget(message);// _ownerMessageQueue->enqueue(message);}Boolean HTTPConnection::isChunkRequested(){ Boolean answer = false; if (_transferEncodingTEValues.size() > 0 && (Contains(_transferEncodingTEValues, String(headerValueTEchunked)) || Contains(_transferEncodingTEValues, String(headerValueTEtrailers)))) answer = true;#ifdef PEGASUS_KERBEROS_AUTHENTICATION CIMKerberosSecurityAssociation *sa = _authInfo->getSecurityAssociation(); if (sa) { answer = false; }#endif return answer;}void HTTPConnection::setSocketWriteTimeout(Uint32 socketWriteTimeout){ _socket->setSocketWriteTimeout(socketWriteTimeout);}// determine if the current code being executed is on the client sideBoolean HTTPConnection::_isClient(){ return strcmp(get_owner().getQueueName(), PEGASUS_QUEUENAME_HTTPCONNECTOR) == 0 ? true : false;}/* * determine if the data read in should be treated as transfer encoded data. * If so, proceed to strip out the transfer encoded meta data within the body * but the headers relating to transfer encoding will remain unchanged. * One should refer to the transfer encoding section of the HTTP protocol * specification to understand the parsing semantics below. * NOTE: this function is coded as a syncronous read! The entire message will * be read in before the message leaves this class and is passed up to the * client application. */void HTTPConnection::_handleReadEventTransferEncoding(){ static const char func[] = "HTTPConnection::_handleReadEventTransferEncoding"; PEG_METHOD_ENTER(TRC_HTTP, func); Uint32 messageLength = _incomingBuffer.size(); Uint32 headerLength = (Uint32) _contentOffset; // return immediately under these conditions: // - Header terminator has not been reached yet (_contentOffset < 0) // - This is a non-transfer encoded message because the content length // has been set from the given header value (_contentLength > 0) // (_contentLength == 0 means bodyless, so return too - section 4.3) // - The message read in so far is <= to the header length // - No transfer encoding has been declared in the header. if (_contentOffset < 0 || _contentLength >= 0 || messageLength <= headerLength || _transferEncodingValues.size() == 0) { PEG_METHOD_EXIT(); return; } // on the first chunk in the message, set the encoding offset to the content // offset if (_transferEncodingChunkOffset == 0) _transferEncodingChunkOffset = (Uint32) _contentOffset; char *headerStart = (char *) _incomingBuffer.getData(); char *messageStart = headerStart; // loop thru the received data (so far) and strip out all chunked meta data. // this logic assumes that the data read in may be only partial at any point // during the parsing. the variable _transferEncodingChunkOffset represents // the byte offset (from the start of the message) of the last NON completed // chunk parsed within the message. Remember that the tcp reader has padded // the buffer with a terminating null for easy string parsing. for (;;) { // we have parsed the length, but not all bytes of chunk have been read // in yet if (_transferEncodingChunkOffset >= messageLength) break; // this is the length from _transferEncodingChunkOffset to the end // of the message (so far). It represents the bytes that have not been // processed yet Uint32 remainderLength = messageLength - _transferEncodingChunkOffset; // the start of the first fully non-parsed chunk of this interation char *chunkLineStart = messageStart + _transferEncodingChunkOffset; char *chunkLineEnd = chunkLineStart; // Find the end of the hex string representing the data portion // length of the current chunk. Note that we must hit at least one // non-hexdigit (except null) to know we have read in the complete // number while (isxdigit(*chunkLineEnd)) chunkLineEnd++; if (! *chunkLineEnd) break; // This is the parsed chunk length in hex. From here on, this many bytes // plus the chunk terminator (AFTER this chunk line is done) must be // read in to constitute a complete chunk in which // _transferEncodingChunkOffset can be incremented to the next chunk Uint32 chunkLengthParsed = (Uint32) strtoul((const char *)chunkLineStart, 0, 16); // this also covers strings stated even larger if (chunkLengthParsed == PEG_NOT_FOUND) _throwEventFailure(HTTP_STATUS_REQUEST_TOO_LARGE, "stated chunk length too large"); char *chunkExtensionStart = chunkLineEnd; chunkLineEnd = strstr(chunkLineEnd, chunkLineTerminator); // If we have not received the chunk line terminator yet, then // return and wait for the next iteration. This is done because the // hex length given only represents the non-meta data, not the chunk // line itself. if (!chunkLineEnd) break; // the token after the hex digit must be either the chunk line // terminator or the chunk extension terminator. If not, the sender // has sent an illegal chunked encoding syntax. if (strncmp(chunkExtensionStart, chunkExtensionTerminator, chunkExtensionTerminatorLength) != 0 && strncmp(chunkExtensionStart, chunkLineTerminator, chunkLineTerminatorLength) != 0) { _throwEventFailure( HTTP_STATUS_BADREQUEST, "missing chunk extension"); } chunkLineEnd += chunkLineTerminatorLength; Uint32 chunkLineLength = chunkLineEnd - chunkLineStart; Uint32 chunkMetaLength = chunkLineLength; if (chunkLengthParsed > 0) chunkMetaLength += chunkTerminatorLength; Uint32 chunkTerminatorOffset = _transferEncodingChunkOffset + chunkLineLength + chunkLengthParsed; // The parsed length represents the non-meta data bytes which starts // after the chunk line terminator has been received. // If we dont have enough remainder bytes to process from the length // parsed then return and wait for the next iteration. // // Also, if this is the last chunk, then we have to know if there // is enough data in here to be able to verify that meta crlf for // the end of the whole chunked message is present. // If chunkLengthParsed + chunkMetaLenght == reminderLength, it // means that there is a space only for meta crlf of the last chunk. // Therefore go back and re-read socket until you get enough data // for at least 2 crlfs. One for the end of the last chunk or // the end of the optional trailer, and one for the end of whole // message. if (chunkLengthParsed + chunkMetaLength >= remainderLength) break; // at this point we have a complete chunk. proceed and strip out // meta-data // NOTE: any time "remove" is called on the buffer, many variables // must be recomputed to reflect the data removed. // remove the chunk length line _incomingBuffer.remove(_transferEncodingChunkOffset, chunkLineLength); messageLength = _incomingBuffer.size(); // always keep the byte after the last data byte null for easy string // processing. messageStart[messageLength] = 0; // recalculate since we just removed the chunk length line chunkTerminatorOffset -= chunkLineLength; // is this the last chunk ? if (chunkLengthParsed == 0) { // We are at the last chunk. The only remaining data should be: // 1. optional trailer first // 2. message terminator (will remain on incoming buffer and // passed up) remainderLength -= chunkLineLength; CIMStatusCode cimStatusCode = CIM_ERR_SUCCESS; Uint32 httpStatusCode = HTTP_STATUSCODE_OK; String httpStatus; String cimErrorValue; // is there an optional trailer ? if (remainderLength > chunkBodyTerminatorLength) { Uint32 trailerLength = remainderLength - chunkBodyTerminatorLength; Uint32 trailerOffset = _transferEncodingChunkOffset; char *trailerStart = messageStart + trailerOffset; char *trailerTerminatorStart = trailerStart + trailerLength - trailerTerminatorLength; // no trailer terminator before end of chunk body ? if (strncmp(trailerTerminatorStart, trailerTerminator, trailerTerminatorLength) != 0) _throwEventFailure(HTTP_STATUS_BADREQUEST, "No chunk trailer terminator received"); Buffer trailer; // add a dummy startLine so that the parser works trailer << " " << headerLineTerminator; char save = trailerStart[trailerLength]; trailerStart[trailerLength] = 0; trailer << trailerStart; trailerStart[trailerLength] = save; _incomingBuffer.remove(trailerOffset, trailerLength); messageLength = _incomingBuffer.size(); messageStart[messageLength] = 0; remainderLength -= trailerLength; // parse the trailer looking for the code and description String startLine; Array<HTTPHeader> headers; Uint32 contentLength = 0; HTTPMessage httpTrailer(trailer); httpTrailer.parse(startLine, headers, contentLength); String cimErrorName = headerNameError; // first look for cim error. this is an http level error Boolean found = false; found = httpTrailer.lookupHeader( headers, cimErrorName, cimErrorValue, true); if (found == true) { // we have a cim error. parse the header to get the // original http level error if any, otherwise, we have // to make one up. Buffer header(messageStart, headerLength); String startLine; Array<HTTPHeader> headers; Uint32 contentLength = 0; HTTPMessage httpHeader(header); httpHeader.parse(startLine, headers, contentLength); String httpVersion; Boolean isValid = httpHeader.parseStatusLine( startLine, httpVersion, httpStatusCode,httpStatus); if (isValid == false || httpStatusCode == 0 || httpStatusCode == HTTP_STATUSCODE_OK) { // ATTN: make up our own http code if not given ? httpStatusCode = (Uint32) HTTP_STATUSCODE_BADREQUEST; httpStatus = HTTP_STATUS_BADREQUEST; } } else { String codeName = headerNameCode; String codeValue; found = httpTrailer.lookupHeader( headers, codeName, codeValue, true); if (found == true && codeValue.size() > 0 && (cimStatusCode = (CIMStatusCode)atoi( codeValue.getCString())) > 0) { HTTPM
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -