XBOX::VError DecompressStream (XBOX::VStream& ioStream)
{
	XBOX::VError error = VE_COMP_LIBRARY_NOT_FOUND;

	if (XBOX::VComponentManager::IsComponentAvailable ((XBOX::CType)CZipComponent::Component_Type))
	{
		CZipComponent *zipComponent = (CZipComponent *)VComponentManager::RetainComponent ((CType)CZipComponent::Component_Type);

		if (zipComponent)
		{
			XBOX::VPtrStream decompressedStream;

			if ((XBOX::VE_OK == (error = ioStream.OpenReading())) && !decompressedStream.OpenWriting())
			{
				error = zipComponent->ExpandStream (&ioStream, &decompressedStream);
				ioStream.CloseReading();
				decompressedStream.CloseWriting();

				if ((XBOX::VE_OK == error) && (!decompressedStream.IsEmpty()))
				{
					if (XBOX::VE_OK == (error = ioStream.OpenWriting()))
					{
						ioStream.SetSize (0);
						ioStream.PutData (decompressedStream.GetDataPtr(), decompressedStream.GetDataSize());
						error = ioStream.CloseWriting();
					}
				}
			}

			zipComponent->Release();
		}
	}

	return error;
}
XBOX::VError CompressStream (XBOX::VStream& ioStream, HTTPCompressionMethod inMethod)
{
	if ((inMethod == COMPRESSION_NONE) || (inMethod > COMPRESSION_LAST_SUPPORTED_METHOD))
		return VE_INVALID_PARAMETER;

	XBOX::VError error = VE_COMP_LIBRARY_NOT_FOUND;

	if (VHTTPServer::GetZipComponentAvailable())
	{
		CZipComponent *zipComponent = VHTTPServer::RetainZipComponent();

		if (NULL != zipComponent)
		{
			XBOX::VPtrStream		compressedStream;
			EZipCompressionLevel	compressionLevel = ((inMethod == COMPRESSION_GZIP) || (inMethod == COMPRESSION_X_GZIP)) ? eCompressionLevel_GZip_BestSpeed : eCompressionLevel_BestSpeed;

			if ((XBOX::VE_OK == (error = ioStream.OpenReading())) && !compressedStream.OpenWriting())
			{
				error = zipComponent->CompressStream (&ioStream, compressionLevel, &compressedStream);
				ioStream.CloseReading();
				compressedStream.CloseWriting();

				if ((XBOX::VE_OK == error) && (!compressedStream.IsEmpty()))
				{
					if (XBOX::VE_OK == (error = ioStream.OpenWriting()))
					{
						ioStream.SetSize (0);
						ioStream.PutData (compressedStream.GetDataPtr(), compressedStream.GetDataSize());
						ioStream.CloseWriting();
					}
				}
			}

			XBOX::QuickReleaseRefCountable (zipComponent);
		}
	}

	return error;
}
XBOX::VError VHTTPMessage::ReadFromStream (XBOX::VStream& inStream, const XBOX::VString& inBoundary)
{
#define	MAX_BUFFER_LENGTH	32768

	const char			HTTP_CR = '\r';
	const char			HTTP_LF = '\n';
	const char			HTTP_CRLF [] = { HTTP_CR, HTTP_LF, 0 };
	const char			HTTP_CRLFCRLF [] = { HTTP_CR, HTTP_LF, HTTP_CR, HTTP_LF, 0 };

	XBOX::VError		streamError = XBOX::VE_OK;
	HTTPParsingState	parsingState;
	XBOX::VError		parsingError = XBOX::VE_OK;
	XBOX::VSize			bufferSize = MAX_BUFFER_LENGTH;
	char *				buffer = (char *)XBOX::vMalloc (bufferSize, 0);
	XBOX::VSize			bufferOffset = 0;
	XBOX::VSize			unreadBytes = 0;
	sLONG				lineLen = 0;
	XBOX::VString		header;
	XBOX::VString		value;
	char *				startLinePtr = NULL;
	char *				endLinePtr = NULL;
	char *				endHeaderPtr = NULL;
	sLONG				endLineSize = sizeof (HTTP_CRLF) - 1;
	sLONG				contentLength = 0;
	void *				bodyContentBuffer = NULL;
	XBOX::VSize			bodyContentSize = 0;
	const sLONG			MAX_REQUEST_ENTITY_SIZE = XBOX::MaxLongInt;
	XBOX::VString		boundaryEnd;
	char *				boundary = NULL;
	bool				stopReadingStream = false;

	if (!inBoundary.IsEmpty())
	{
		boundaryEnd.AppendString ("--");
		boundaryEnd.AppendString (inBoundary);
		boundary = new char[boundaryEnd.GetLength() + 1];
		if (NULL != boundary)
			boundaryEnd.ToCString (boundary, boundaryEnd.GetLength() + 1);
	}

	if (NULL == buffer)
		return XBOX::VE_MEMORY_FULL;

	parsingState = PS_ReadingHeaders;

	XBOX::StErrorContextInstaller errorContext (XBOX::VE_STREAM_EOF, XBOX::VE_OK);

	bool isAlreadyReading = inStream.IsReading();

	if (!isAlreadyReading)
		streamError = inStream.OpenReading();

	while ((XBOX::VE_OK == streamError) && !stopReadingStream)
	{
		if (0 == unreadBytes)
			bufferOffset = 0;

		bufferSize = MAX_BUFFER_LENGTH - bufferOffset;

		streamError = inStream.GetData (buffer + bufferOffset, &bufferSize);

		unreadBytes = (bufferSize + bufferOffset);
		bufferOffset = 0;

		while ((unreadBytes > 0) && (XBOX::VE_OK == parsingError))
		{
			if (parsingState <= PS_ReadingHeaders)
			{
				startLinePtr = buffer + bufferOffset;
				endLinePtr = strstr (startLinePtr, HTTP_CRLF);

				if ((NULL != endLinePtr) && (NULL == endHeaderPtr))
					endHeaderPtr = strstr (startLinePtr, HTTP_CRLFCRLF);
			}

			/* Start to parse the Status-Line */
			switch (parsingState)
			{
			case PS_ReadingHeaders:
				{
					if (NULL != endLinePtr)
					{
						if (startLinePtr != (endHeaderPtr + endLineSize))
						{
							if (_ExtractHeaderValuePair (startLinePtr, endLinePtr, header, value))
							{
								GetHeaders().SetHeaderValue (header, value, false);
							}
						}

						else /*if (startLinePtr == endHeaderPtr)*/
						{
							parsingState = PS_ReadingBody;
							XBOX::VString contentLengthString;
							if (GetHeaders().GetHeaderValue (STRING_HEADER_CONTENT_LENGTH, contentLengthString))
								contentLength = HTTPTools::GetLongFromString (contentLengthString);
						}
					}
					break;
				}

			case PS_ReadingBody:
				{
					if (!boundaryEnd.IsEmpty())
					{
						if (NULL != boundary)
						{
							char *endBoundaryPtr = memstr (buffer + bufferOffset, unreadBytes, boundary, strlen (boundary));
							if (NULL != endBoundaryPtr)
							{
								XBOX::VSize nbBytesToCopy  = (endBoundaryPtr - (buffer + bufferOffset));
								inStream.UngetData (endBoundaryPtr, unreadBytes - nbBytesToCopy);
								unreadBytes = nbBytesToCopy;
								if (NULL != memstr (endBoundaryPtr - 2, 2, HTTP_CRLF, 2))
									unreadBytes -= 2;	// Skip CRLF after boundary part
								stopReadingStream = true;
							}
						}
					}

					if (NULL == bodyContentBuffer)
					{
						// There's no Content-Length field in header
						if (0 == contentLength)
						{
							bodyContentBuffer = XBOX::vMalloc (bufferSize, 0);
							bodyContentSize = 0;
						}
						// There's one Content-Length, just check it match limits
						else if ((contentLength > 0) && (contentLength < MAX_REQUEST_ENTITY_SIZE))
						{
							bodyContentBuffer = XBOX::vMalloc (contentLength, 0);
							bodyContentSize = 0;
						}
					}

					if ((NULL != bodyContentBuffer) && (bodyContentSize + unreadBytes < MAX_REQUEST_ENTITY_SIZE))
					{
						XBOX::VSize nbBytesToCopy = unreadBytes;
						if (bodyContentSize + nbBytesToCopy > contentLength)
							bodyContentBuffer = XBOX::vRealloc (bodyContentBuffer, bodyContentSize + nbBytesToCopy);

						memcpy ((char *)(bodyContentBuffer) + bodyContentSize, buffer + bufferOffset, unreadBytes);
						bodyContentSize += unreadBytes;
						bufferOffset = unreadBytes = 0;
					}
					else
					{
						parsingError = XBOX::VE_MEMORY_FULL;

						if (NULL != bodyContentBuffer)
						{
							XBOX::vFree (bodyContentBuffer);
							bodyContentBuffer = NULL;
						}
					}
					break;
				}
			}

			if (XBOX::VE_OK != parsingError)
				break;

			if (NULL != endLinePtr)
			{
				lineLen = (endLinePtr - startLinePtr) + endLineSize; // to skip CRLF;
				bufferOffset += lineLen;
				unreadBytes -= lineLen;
				endLinePtr = NULL;
			}
			else
			{
				if (bufferOffset > 0)
				{
					memmove (buffer, buffer + bufferOffset, unreadBytes);
					buffer[unreadBytes] = 0;
				}
				bufferOffset = unreadBytes;
				break;
			}
		}

		if (XBOX::VE_OK != parsingError)
			break;
	}

	if (!isAlreadyReading)
		inStream.CloseReading();

	if (XBOX::VE_STREAM_EOF == streamError)
		streamError = XBOX::VE_OK;

	if (!parsingError && !streamError)
	{
		if (NULL != bodyContentBuffer)
		{
#if VERSIONDEBUG
			if ((contentLength > 0) && (bodyContentSize != contentLength))
				assert (false);
#endif
			GetBody().SetDataPtr (bodyContentBuffer, bodyContentSize);

			XBOX::VString	contentType;
			XBOX::CharSet	charSet = XBOX::VTC_UNKNOWN;

			/* Set VStream charset according to content-type header other else set default charset to UTF-8 */
			if ((!GetHeaders().GetContentType (contentType, &charSet)) || (XBOX::VTC_UNKNOWN == charSet))
				charSet = XBOX::VTC_UTF_8;
			GetBody().SetCharSet (charSet);
		}

		parsingState = PS_ParsingFinished;
	}
	else
	{
		if (NULL != bodyContentBuffer)
			XBOX::vFree (bodyContentBuffer);
	}

	delete [] boundary;
	boundary = NULL;

	XBOX::vFree (buffer);
	buffer = NULL;

	return streamError;

#undef MAX_BUFFER_LENGTH
}
Exemplo n.º 4
0
XBOX::VError VMIMEMessage::ToStream (XBOX::VStream& outStream, sLONG inEncoding)
{
	XBOX::VError error = XBOX::VE_OK;

	if (XBOX::VE_OK == outStream.OpenWriting())
	{
		outStream.SetCarriageReturnMode(eCRM_CRLF);
		if (!fMIMEParts.empty())
		{
			XBOX::VString	string;
			XBOX::VString	charsetName;
			bool			bEncodeBody;	// Encode using base64.

			for (XBOX::VectorOfMIMEPart::const_iterator it = fMIMEParts.begin(); it != fMIMEParts.end(); ++it)
			{
				outStream.PutPrintf ("\r\n--%S\r\n", &fBoundary);

				string.FromCString ("Content-Type: ");
				string.AppendString ((*it)->GetMediaType());
 
				if (!(*it)->GetFileName().IsEmpty())
				{
					string.AppendCString ("; name=\"");
					if (!(*it)->GetName().IsEmpty())
						string.AppendString ((*it)->GetName());
					else
						string.AppendString ((*it)->GetFileName());

					string.AppendCString("\"\r\nContent-Disposition: ");
					string.AppendCString((*it)->IsInline() ? "inline; " : "attachment; ");					
					string.AppendCString("filename=\"");

					string.AppendString ((*it)->GetFileName());
					string.AppendCString ("\"\r\n");

					if (inEncoding == ENCODING_BINARY) {

						string.AppendCString ("Content-Transfer-Encoding: 8bit\r\n");
						bEncodeBody = false;

					} else {

						if ((inEncoding == ENCODING_BINARY_ONLY) && ((*it)->GetMediaTypeKind() == MIMETYPE_TEXT))
						{
							bEncodeBody = false;
						}
						else
						{
							string.AppendCString ("Content-Transfer-Encoding: base64\r\n");
							bEncodeBody = true;
						}
					}
				}
				else
				{
					if ((*it)->GetMediaTypeCharSet() != XBOX::VTC_UNKNOWN)
					{
						string.AppendCString ("; charset=\"");
						XBOX::VTextConverters::Get()->GetNameFromCharSet ((*it)->GetMediaTypeCharSet(), charsetName);
						string.AppendString (charsetName);
						string.AppendCString ("\"");
					}

					if (!(*it)->GetName().IsEmpty()) {

						string.AppendCString("; name=\"");
						string.AppendString((*it)->GetName());
						string.AppendCString("\"");

					}

					string.AppendCString ("\r\n");

					if ((*it)->IsInline())

						string.AppendCString("Content-Disposition: inline\r\n");
						
					if (inEncoding == ENCODING_7BIT || ((inEncoding == ENCODING_BINARY_ONLY) && ((*it)->GetMediaTypeKind() != MIMETYPE_TEXT))) {

						string.AppendCString ("Content-Transfer-Encoding: base64\r\n");
						bEncodeBody = true;

					} else {

						string.AppendCString("Content-Transfer-Encoding: 8bit\r\n");
						bEncodeBody = false;

					}
				}

				if ((*it)->GetContentID().GetLength()) {

					string.AppendCString("Content-ID: <");
					string.AppendString((*it)->GetContentID());
					string.AppendCString(">\r\n");

				}

				string.AppendCString ("\r\n");

				outStream.PutText (string);

				if (bEncodeBody)
				{
					XBOX::VMemoryBuffer<> buffer;
					if (XBOX::Base64Coder::Encode ((*it)->GetData().GetDataPtr(), (*it)->GetData().GetDataSize(), buffer, kBASE64_QUADS_PER_LINE))
					{
						outStream.PutData (buffer.GetDataPtr(), buffer.GetDataSize());
					}
				}
				else
				{
					outStream.PutData ((*it)->GetData().GetDataPtr(), (*it)->GetData().GetDataSize());
				}
			}

			outStream.PutPrintf ("\r\n--%S--\r\n", &fBoundary);
		}

		outStream.CloseWriting();
	}

	return error;
}