version 1.87, 2005/01/13 15:08:51
|
version 1.88, 2005/01/16 02:50:46
|
|
|
// Sushma Fernandes, IBM (sushma@hp.com) for Bug#2057 | // Sushma Fernandes, IBM (sushma@hp.com) for Bug#2057 |
// Brian G. Campbell, EMC (campbell_brian@emc.com) - PEP140/phase2 | // Brian G. Campbell, EMC (campbell_brian@emc.com) - PEP140/phase2 |
// Amit Arora, IBM (amita@in.ibm.com) for Bug#2541 | // Amit Arora, IBM (amita@in.ibm.com) for Bug#2541 |
|
// David Dillard, VERITAS Software Corp. (david.dillard@veritas.com) |
// | // |
//%///////////////////////////////////////////////////////////////////////////// | //%///////////////////////////////////////////////////////////////////////////// |
| |
|
|
static const char headerValueSeparator[] = ", "; | static const char headerValueSeparator[] = ", "; |
static const char headerLineTerminator[] = CRLF; | static const char headerLineTerminator[] = CRLF; |
static const char headerTerminator[] = CRLF CRLF; | static const char headerTerminator[] = CRLF CRLF; |
static const Sint8 chunkLineTerminator[] = CRLF; |
static const char chunkLineTerminator[] = CRLF; |
static const Sint8 chunkTerminator[] = CRLF; |
static const char chunkTerminator[] = CRLF; |
static const Sint8 chunkBodyTerminator[] = CRLF; |
static const char chunkBodyTerminator[] = CRLF; |
static const Sint8 trailerTerminator[] = CRLF; |
static const char trailerTerminator[] = CRLF; |
static const Sint8 chunkExtensionTerminator[] = ";"; |
static const char chunkExtensionTerminator[] = ";"; |
| |
// string sizes | // string sizes |
| |
|
|
static const char func[] = "HTTPConnection::_handleWriteEvent"; | static const char func[] = "HTTPConnection::_handleWriteEvent"; |
String httpStatus; | String httpStatus; |
HTTPMessage& httpMessage = *(HTTPMessage*)&message; | HTTPMessage& httpMessage = *(HTTPMessage*)&message; |
Array<Sint8>& buffer = httpMessage.message; |
Array<char>& buffer = httpMessage.message; |
Boolean isFirst = message.isFirst(); | Boolean isFirst = message.isFirst(); |
Boolean isLast = message.isComplete(); | Boolean isLast = message.isComplete(); |
Sint32 totalBytesWritten = 0; | Sint32 totalBytesWritten = 0; |
|
|
// 3 handler.complete() : deliver() + isLast = true | // 3 handler.complete() : deliver() + isLast = true |
| |
Uint32 bytesRemaining = messageLength; | Uint32 bytesRemaining = messageLength; |
Sint8 *messageStart = (Sint8 *)buffer.getData(); |
char *messageStart = (char *) buffer.getData(); |
Uint32 bytesToWrite = httpTcpBufferSize; | Uint32 bytesToWrite = httpTcpBufferSize; |
Uint32 messageIndex = message.getIndex(); | Uint32 messageIndex = message.getIndex(); |
Boolean isChunkResponse = false; | Boolean isChunkResponse = false; |
|
|
{ | { |
// for null termination | // for null termination |
buffer.reserveCapacity(messageLength + 1); | buffer.reserveCapacity(messageLength + 1); |
messageStart = (Sint8 *)buffer.getData(); |
messageStart = (char *) buffer.getData(); |
messageStart[messageLength] = 0; |
buffer[messageLength] = 0; |
| |
if (isFirst == true) | if (isFirst == true) |
{ | { |
|
|
char s[21]; | char s[21]; |
sprintf(s, "%u", code); | sprintf(s, "%u", code); |
String httpStatus(s); | String httpStatus(s); |
Array<Sint8> message = XmlWriter::formatHttpErrorRspMessage |
Array<char> message = XmlWriter::formatHttpErrorRspMessage |
(httpStatus, String(), httpDetail); | (httpStatus, String(), httpDetail); |
messageLength = message.size(); | messageLength = message.size(); |
message.reserveCapacity(messageLength+1); | message.reserveCapacity(messageLength+1); |
messageStart =(Sint8 *) message.getData(); |
messageStart = (char *) message.getData(); |
messageStart[messageLength] = 0; |
message[messageLength] = 0; |
} | } |
cimException = CIMException(cimException.getCode(), | cimException = CIMException(cimException.getCode(), |
String(messageStart, messageLength)); | String(messageStart, messageLength)); |
|
|
_incomingBuffer.appendArray(buffer); | _incomingBuffer.appendArray(buffer); |
buffer.clear(); | buffer.clear(); |
// null terminate | // null terminate |
messageStart = (Sint8 *) _incomingBuffer.getData(); |
messageStart = (char *) _incomingBuffer.getData(); |
messageStart[messageLength] = 0; |
_incomingBuffer[messageLength] = 0; |
// put back in buffer, so the httpMessage parser can work below | // put back in buffer, so the httpMessage parser can work below |
_incomingBuffer.swap(buffer); | _incomingBuffer.swap(buffer); |
} | } |
|
|
buffer.reserveCapacity(messageLength+1); | buffer.reserveCapacity(messageLength+1); |
buffer.append(messageStart, messageLength); | buffer.append(messageStart, messageLength); |
// null terminate | // null terminate |
messageStart = (Sint8 *) buffer.getData(); |
messageStart = (char *) buffer.getData(); |
messageStart[messageLength] = 0; |
buffer[messageLength] = 0; |
} | } |
bytesRemaining = messageLength; | bytesRemaining = messageLength; |
} | } |
|
|
Boolean isValid = httpMessage. | Boolean isValid = httpMessage. |
parseStatusLine(startLine, httpVersion, httpStatusCode,reasonPhrase); | parseStatusLine(startLine, httpVersion, httpStatusCode,reasonPhrase); |
Uint32 headerLength = messageLength - contentLength; | Uint32 headerLength = messageLength - contentLength; |
Sint8 save = messageStart[headerLength]; |
char save = messageStart[headerLength]; |
messageStart[headerLength] = 0; | messageStart[headerLength] = 0; |
| |
Sint8 *contentLengthStart = |
char *contentLengthStart = |
strstr(messageStart, headerNameContentLength); | strstr(messageStart, headerNameContentLength); |
| |
Sint8 *contentLengthEnd = contentLengthStart ? |
char* contentLengthEnd = contentLengthStart ? |
strstr(contentLengthStart, headerLineTerminator) : 0; | strstr(contentLengthStart, headerLineTerminator) : 0; |
| |
messageStart[headerLength] = save; | messageStart[headerLength] = save; |
|
|
if (isChunkResponse == false) | if (isChunkResponse == false) |
{ | { |
// overwrite the content length number with the actual byte count | // overwrite the content length number with the actual byte count |
Sint8 *contentLengthNumberStart = contentLengthStart + |
char *contentLengthNumberStart = contentLengthStart + |
headerNameContentLengthLength + headerNameTerminatorLength; | headerNameContentLengthLength + headerNameTerminatorLength; |
char format[6]; | char format[6]; |
sprintf (format, "%%.%uu", numberAsStringLength); | sprintf (format, "%%.%uu", numberAsStringLength); |
|
|
if (contentLanguages != ContentLanguages::EMPTY) | if (contentLanguages != ContentLanguages::EMPTY) |
{ | { |
// we must insert the content-language into the header | // we must insert the content-language into the header |
Array<Sint8> contentLanguagesString; |
Array<char> contentLanguagesString; |
| |
// this is the keyword:value(s) + header line terminator | // this is the keyword:value(s) + header line terminator |
contentLanguagesString << headerNameContentLanguage << | contentLanguagesString << headerNameContentLanguage << |
|
|
messageLength = contentLanguagesString.size() + buffer.size(); | messageLength = contentLanguagesString.size() + buffer.size(); |
buffer.reserveCapacity(messageLength+1); | buffer.reserveCapacity(messageLength+1); |
messageLength = contentLanguagesString.size(); | messageLength = contentLanguagesString.size(); |
messageStart = (Sint8 *)contentLanguagesString.getData(); |
messageStart = (char *)contentLanguagesString.getData(); |
// insert the content language line before end of header | // insert the content language line before end of header |
// note: this can be expensive on large payloads | // note: this can be expensive on large payloads |
buffer.insert(insertOffset, messageStart, messageLength); | buffer.insert(insertOffset, messageStart, messageLength); |
messageLength = buffer.size(); | messageLength = buffer.size(); |
// null terminate | // null terminate |
messageStart = (Sint8 *) buffer.getData(); |
messageStart = (char *) buffer.getData(); |
messageStart[messageLength] = 0; | messageStart[messageLength] = 0; |
bytesRemaining = messageLength; | bytesRemaining = messageLength; |
} // if there were any content languages | } // if there were any content languages |
|
|
//t.run(); | //t.run(); |
| |
static const char errorSocket[] = "socket write error"; | static const char errorSocket[] = "socket write error"; |
Sint8 *sendStart = messageStart; |
char *sendStart = messageStart; |
Sint32 bytesWritten = 0; | Sint32 bytesWritten = 0; |
| |
if (isFirst == true && isChunkResponse == true && bytesToWrite > 0) | if (isFirst == true && isChunkResponse == true && bytesToWrite > 0) |
|
|
bytesRemaining -= bytesWritten; | bytesRemaining -= bytesWritten; |
| |
// put in trailer header. | // put in trailer header. |
Array<Sint8> trailer; |
Array<char> trailer; |
trailer << headerNameTrailer << headerNameTerminator << | trailer << headerNameTrailer << headerNameTerminator << |
_mpostPrefix << headerNameCode << headerValueSeparator << | _mpostPrefix << headerNameCode << headerValueSeparator << |
_mpostPrefix << headerNameDescription << headerValueSeparator << | _mpostPrefix << headerNameDescription << headerValueSeparator << |
headerNameContentLanguage << headerLineTerminator; | headerNameContentLanguage << headerLineTerminator; |
sendStart = (Sint8 *)trailer.getData(); |
sendStart = (char *) trailer.getData(); |
bytesToWrite = trailer.size(); | bytesToWrite = trailer.size(); |
bytesWritten = _socket->write(sendStart, bytesToWrite); | bytesWritten = _socket->write(sendStart, bytesToWrite); |
| |
|
|
{ | { |
// send chunk terminator, on the last chunk, it is the chunk body | // send chunk terminator, on the last chunk, it is the chunk body |
// terminator | // terminator |
Array<Sint8> trailer; |
Array<char> trailer; |
trailer << chunkLineTerminator; | trailer << chunkLineTerminator; |
| |
// on the last chunk, attach the last chunk termination sequence: | // on the last chunk, attach the last chunk termination sequence: |
|
|
trailer << chunkBodyTerminator; | trailer << chunkBodyTerminator; |
} // if isLast | } // if isLast |
| |
sendStart = (Sint8 *)trailer.getData(); |
sendStart = (char *) trailer.getData(); |
Sint32 chunkBytesToWrite = (Sint32) trailer.size(); | Sint32 chunkBytesToWrite = (Sint32) trailer.size(); |
bytesWritten = _socket->write(sendStart, chunkBytesToWrite); | bytesWritten = _socket->write(sendStart, chunkBytesToWrite); |
if (bytesWritten < 0) | if (bytesWritten < 0) |
|
|
if (_transferEncodingChunkOffset == 0) | if (_transferEncodingChunkOffset == 0) |
_transferEncodingChunkOffset = (Uint32) _contentOffset; | _transferEncodingChunkOffset = (Uint32) _contentOffset; |
| |
Sint8 *headerStart = (Sint8 *) _incomingBuffer.getData(); |
char *headerStart = (char *) _incomingBuffer.getData(); |
Sint8 *messageStart = headerStart; |
char *messageStart = headerStart; |
| |
// loop thru the received data (so far) and strip out all chunked meta data. | // 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 | // this logic assumes that the data read in may be only partial at any point |
|
|
Uint32 remainderLength = messageLength - _transferEncodingChunkOffset; | Uint32 remainderLength = messageLength - _transferEncodingChunkOffset; |
| |
// the start of the first fully non-parsed chunk of this interation | // the start of the first fully non-parsed chunk of this interation |
Sint8 *chunkLineStart = messageStart + _transferEncodingChunkOffset; |
char *chunkLineStart = messageStart + _transferEncodingChunkOffset; |
Sint8 *chunkLineEnd = chunkLineStart; |
char *chunkLineEnd = chunkLineStart; |
| |
// Find the end of the hex string representing the data portion length of | // 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 | // the current chunk. Note that we must hit at least one non-hexdigit |
|
|
_throwEventFailure(HTTP_STATUS_REQUEST_TOO_LARGE, | _throwEventFailure(HTTP_STATUS_REQUEST_TOO_LARGE, |
"stated chunk length too large"); | "stated chunk length too large"); |
| |
Sint8 *chunkExtensionStart = chunkLineEnd; |
char *chunkExtensionStart = chunkLineEnd; |
chunkLineEnd = strstr(chunkLineEnd, chunkLineTerminator); | chunkLineEnd = strstr(chunkLineEnd, chunkLineTerminator); |
| |
// If we have not received the chunk line terminator yet, then return and | // If we have not received the chunk line terminator yet, then return and |
|
|
{ | { |
Uint32 trailerLength = remainderLength - chunkBodyTerminatorLength; | Uint32 trailerLength = remainderLength - chunkBodyTerminatorLength; |
Uint32 trailerOffset = _transferEncodingChunkOffset; | Uint32 trailerOffset = _transferEncodingChunkOffset; |
Sint8 *trailerStart = messageStart + trailerOffset; |
char *trailerStart = messageStart + trailerOffset; |
Sint8 *trailerTerminatorStart = trailerStart + trailerLength - |
char *trailerTerminatorStart = trailerStart + trailerLength - |
trailerTerminatorLength; | trailerTerminatorLength; |
| |
// no trailer terminator before end of chunk body ? | // no trailer terminator before end of chunk body ? |
|
|
_throwEventFailure(HTTP_STATUS_BADREQUEST, | _throwEventFailure(HTTP_STATUS_BADREQUEST, |
"No chunk trailer terminator received"); | "No chunk trailer terminator received"); |
| |
Array<Sint8> trailer; |
Array<char> trailer; |
// add a dummy startLine so that the parser works | // add a dummy startLine so that the parser works |
trailer << " " << headerLineTerminator; | trailer << " " << headerLineTerminator; |
| |
|
|
// we have a cim error. parse the header to get the original http | // we have a cim error. parse the header to get the original http |
// level error if any, otherwise, we have to make one up. | // level error if any, otherwise, we have to make one up. |
| |
Array<Sint8> header(messageStart, headerLength); |
Array<char> header(messageStart, headerLength); |
String startLine; | String startLine; |
Array<HTTPHeader> headers; | Array<HTTPHeader> headers; |
Uint32 contentLength = 0; | Uint32 contentLength = 0; |
|
|
} // else not a cim error | } // else not a cim error |
} // if optional trailer present | } // if optional trailer present |
| |
Sint8 *chunkBodyTerminatorStart = |
char *chunkBodyTerminatorStart = |
messageStart + _transferEncodingChunkOffset; | messageStart + _transferEncodingChunkOffset; |
| |
// look for chunk body terminator | // look for chunk body terminator |
|
|
| |
_incomingBuffer.append(headerLineTerminator, headerLineTerminatorLength); | _incomingBuffer.append(headerLineTerminator, headerLineTerminatorLength); |
// null terminate - the buffer is at least as long after removing | // null terminate - the buffer is at least as long after removing |
Sint8 *data = (Sint8 *)_incomingBuffer.getData(); |
char *data = (char *)_incomingBuffer.getData(); |
data[_incomingBuffer.size()] = 0; | data[_incomingBuffer.size()] = 0; |
_contentLength = 0; | _contentLength = 0; |
_contentOffset = 0; | _contentOffset = 0; |
|
|
| |
Tracer::trace(__FILE__, __LINE__, TRC_HTTP, Tracer::LEVEL2, combined); | Tracer::trace(__FILE__, __LINE__, TRC_HTTP, Tracer::LEVEL2, combined); |
_requestCount++; | _requestCount++; |
Array<Sint8> message; |
Array<char> message; |
message = XmlWriter::formatHttpErrorRspMessage(httpStatus, cimError, | message = XmlWriter::formatHttpErrorRspMessage(httpStatus, cimError, |
httpDetail); | httpDetail); |
HTTPMessage* httpMessage = new HTTPMessage(message); | HTTPMessage* httpMessage = new HTTPMessage(message); |
|
|
_incomingBuffer.reserveCapacity(size + 1); | _incomingBuffer.reserveCapacity(size + 1); |
_incomingBuffer.append(buffer, n); | _incomingBuffer.append(buffer, n); |
// put a null on it. This is safe sice we have reserved an extra byte | // put a null on it. This is safe sice we have reserved an extra byte |
Sint8 *data = (Sint8 *)_incomingBuffer.getData(); |
char *data = (char *)_incomingBuffer.getData(); |
data[size] = 0; | data[size] = 0; |
} | } |
| |
|
|
// so it is just fine if it blocks. << Tue Oct 7 09:48:06 2003 mdd >> | // so it is just fine if it blocks. << Tue Oct 7 09:48:06 2003 mdd >> |
//------------------------------------------------------------ | //------------------------------------------------------------ |
| |
const Array<Sint8>& buffer = httpMessage->message; |
const Array<char>& buffer = httpMessage->message; |
| |
const Uint32 CHUNK_SIZE = 16 * 1024; | const Uint32 CHUNK_SIZE = 16 * 1024; |
| |