mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
452 lines
11 KiB
452 lines
11 KiB
/*++
|
|
|
|
Copyright (c) 2000-2001 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
fastio.h
|
|
|
|
Abstract:
|
|
|
|
This module contains declarations related to fast I/O.
|
|
|
|
Author:
|
|
|
|
Chun Ye (chunye) 09-Dec-2000
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
|
|
#ifndef _FASTIO_H_
|
|
#define _FASTIO_H_
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
|
|
//
|
|
// Some useful macroes.
|
|
//
|
|
|
|
#define IS_LENGTH_SPECIFIED( pKnownHeaders ) \
|
|
(pKnownHeaders[HttpHeaderContentLength].RawValueLength > 0)
|
|
|
|
#define IS_CHUNK_SPECIFIED( pKnownHeaders ) \
|
|
(pKnownHeaders[HttpHeaderTransferEncoding].RawValueLength > 0 && \
|
|
0 == _strnicmp( \
|
|
pKnownHeaders[HttpHeaderTransferEncoding].pRawValue, \
|
|
"chunked", \
|
|
strlen("chunked") \
|
|
)) \
|
|
|
|
|
|
//
|
|
// Inline functions to allocate/free a fast tracker.
|
|
//
|
|
|
|
__inline
|
|
PUL_FULL_TRACKER
|
|
FASTCALL
|
|
UlpAllocateFastTracker(
|
|
IN ULONG FixedHeaderLength,
|
|
IN CCHAR SendIrpStackSize
|
|
)
|
|
{
|
|
PUL_FULL_TRACKER pTracker;
|
|
ULONG SpaceLength;
|
|
ULONG MaxFixedHeaderSize;
|
|
USHORT MaxSendIrpSize;
|
|
CCHAR MaxSendIrpStackSize;
|
|
|
|
//
|
|
// Sanity check.
|
|
//
|
|
|
|
PAGED_CODE();
|
|
|
|
if (FixedHeaderLength > g_UlMaxFixedHeaderSize ||
|
|
SendIrpStackSize > DEFAULT_MAX_IRP_STACK_SIZE)
|
|
{
|
|
MaxFixedHeaderSize = MAX(FixedHeaderLength, g_UlMaxFixedHeaderSize);
|
|
MaxSendIrpStackSize = MAX(SendIrpStackSize, DEFAULT_MAX_IRP_STACK_SIZE);
|
|
MaxSendIrpSize = (USHORT)ALIGN_UP(IoSizeOfIrp(MaxSendIrpStackSize), PVOID);
|
|
|
|
SpaceLength =
|
|
ALIGN_UP(sizeof(UL_FULL_TRACKER), PVOID) +
|
|
MaxSendIrpSize +
|
|
MaxFixedHeaderSize +
|
|
g_UlMaxVariableHeaderSize +
|
|
g_UlMaxCopyThreshold +
|
|
g_UlFixedHeadersMdlLength +
|
|
g_UlVariableHeadersMdlLength +
|
|
g_UlContentMdlLength;
|
|
|
|
pTracker = (PUL_FULL_TRACKER)UL_ALLOCATE_POOL(
|
|
NonPagedPool,
|
|
SpaceLength,
|
|
UL_FULL_TRACKER_POOL_TAG
|
|
);
|
|
|
|
if (pTracker)
|
|
{
|
|
pTracker->Signature = UL_FULL_TRACKER_POOL_TAG;
|
|
pTracker->IrpContext.Signature = UL_IRP_CONTEXT_SIGNATURE;
|
|
pTracker->IsFromLookaside = FALSE;
|
|
pTracker->IsFromRequest = FALSE;
|
|
pTracker->AuxilaryBufferLength =
|
|
MaxFixedHeaderSize +
|
|
g_UlMaxVariableHeaderSize +
|
|
g_UlMaxCopyThreshold;
|
|
|
|
UlInitializeFullTrackerPool( pTracker, MaxSendIrpStackSize );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pTracker = UlPplAllocateFullTracker();
|
|
|
|
if (pTracker)
|
|
{
|
|
ASSERT(pTracker->Signature == MAKE_FREE_TAG(UL_FULL_TRACKER_POOL_TAG));
|
|
pTracker->Signature = UL_FULL_TRACKER_POOL_TAG;
|
|
pTracker->pLogData = NULL;
|
|
|
|
// BUGBUG: I know we're trying to squeeze every last cycle
|
|
// out of the fast path, but can we really get away with
|
|
// this little initialization?
|
|
}
|
|
}
|
|
|
|
return pTracker;
|
|
} // UlpAllocateFastTracker
|
|
|
|
|
|
__inline
|
|
VOID
|
|
FASTCALL
|
|
UlpFreeFastTracker(
|
|
IN PUL_FULL_TRACKER pTracker
|
|
)
|
|
{
|
|
//
|
|
// Sanity check.
|
|
//
|
|
|
|
PAGED_CODE();
|
|
|
|
ASSERT( IS_VALID_FULL_TRACKER( pTracker ) );
|
|
|
|
if (pTracker->pLogData)
|
|
{
|
|
UlDestroyLogDataBuffer( pTracker->pLogData );
|
|
}
|
|
|
|
if (pTracker->IsFromRequest == FALSE)
|
|
{
|
|
if (pTracker->IsFromLookaside)
|
|
{
|
|
pTracker->Signature = MAKE_FREE_TAG(UL_FULL_TRACKER_POOL_TAG);
|
|
UlPplFreeFullTracker( pTracker );
|
|
}
|
|
else
|
|
{
|
|
UL_FREE_POOL_WITH_SIG( pTracker, UL_FULL_TRACKER_POOL_TAG );
|
|
}
|
|
}
|
|
} // UlpFreeFastTracker
|
|
|
|
|
|
//
|
|
// Dispatch routines for fast I/O.
|
|
//
|
|
|
|
extern FAST_IO_DISPATCH UlFastIoDispatch;
|
|
|
|
|
|
//
|
|
// Fast I/O routines.
|
|
//
|
|
|
|
BOOLEAN
|
|
UlFastIoDeviceControl (
|
|
IN PFILE_OBJECT pFileObject,
|
|
IN BOOLEAN Wait,
|
|
IN PVOID pInputBuffer OPTIONAL,
|
|
IN ULONG InputBufferLength,
|
|
OUT PVOID pOutputBuffer OPTIONAL,
|
|
IN ULONG OutputBufferLength,
|
|
IN ULONG IoControlCode,
|
|
OUT PIO_STATUS_BLOCK pIoStatus,
|
|
IN PDEVICE_OBJECT pDeviceObject
|
|
);
|
|
|
|
|
|
BOOLEAN
|
|
UlSendHttpResponseFastIo(
|
|
IN PFILE_OBJECT pFileObject,
|
|
IN BOOLEAN Wait,
|
|
IN PVOID pInputBuffer OPTIONAL,
|
|
IN ULONG InputBufferLength,
|
|
OUT PVOID pOutputBuffer OPTIONAL,
|
|
IN ULONG OutputBufferLength,
|
|
OUT PIO_STATUS_BLOCK pIoStatus,
|
|
IN PDEVICE_OBJECT pDeviceObject,
|
|
IN BOOLEAN RawResponse
|
|
);
|
|
|
|
BOOLEAN
|
|
UlReceiveHttpRequestFastIo(
|
|
IN PFILE_OBJECT pFileObject,
|
|
IN BOOLEAN Wait,
|
|
IN PVOID pInputBuffer OPTIONAL,
|
|
IN ULONG InputBufferLength,
|
|
OUT PVOID pOutputBuffer OPTIONAL,
|
|
IN ULONG OutputBufferLength,
|
|
OUT PIO_STATUS_BLOCK pIoStatus,
|
|
IN PDEVICE_OBJECT pDeviceObject
|
|
);
|
|
|
|
|
|
//
|
|
// Private prototypes.
|
|
//
|
|
|
|
NTSTATUS
|
|
UlpFastSendHttpResponse(
|
|
IN PHTTP_RESPONSE pUserResponse OPTIONAL,
|
|
IN PHTTP_LOG_FIELDS_DATA pLogData OPTIONAL,
|
|
IN PHTTP_DATA_CHUNK pDataChunk,
|
|
IN ULONG ChunkCount,
|
|
IN ULONG Flags,
|
|
IN PUL_INTERNAL_REQUEST pRequest,
|
|
IN PIRP pUserIrp OPTIONAL,
|
|
OUT PULONG BytesSent
|
|
);
|
|
|
|
VOID
|
|
UlpRestartFastSendHttpResponse(
|
|
IN PVOID pCompletionContext,
|
|
IN NTSTATUS Status,
|
|
IN ULONG_PTR Information
|
|
);
|
|
|
|
VOID
|
|
UlpFastSendCompleteWorker(
|
|
IN PUL_WORK_ITEM pWorkItem
|
|
);
|
|
|
|
NTSTATUS
|
|
UlpFastReceiveHttpRequest(
|
|
IN HTTP_REQUEST_ID RequestId,
|
|
IN PUL_APP_POOL_PROCESS pProcess,
|
|
IN PVOID pOutputBuffer,
|
|
IN ULONG OutputBufferLength,
|
|
OUT PULONG pBytesRead
|
|
);
|
|
|
|
NTSTATUS
|
|
UlpFastCopyHttpRequest(
|
|
IN PUL_INTERNAL_REQUEST pRequest,
|
|
IN PVOID pOutputBuffer,
|
|
IN ULONG OutputBufferLength,
|
|
OUT PULONG pBytesRead
|
|
);
|
|
|
|
|
|
//
|
|
// An inline function to generate the content-length string.
|
|
//
|
|
|
|
__inline
|
|
ULONG
|
|
FASTCALL
|
|
UlpFastGenerateContentLength(
|
|
IN PCHAR LengthString,
|
|
IN ULONG Length
|
|
)
|
|
{
|
|
ASSERT( ALIGN_UP_POINTER(LengthString, ULONG) == (PVOID)LengthString );
|
|
ASSERT( Length < 100000 );
|
|
|
|
if (Length >= 10000)
|
|
{
|
|
*((PULONG)LengthString) = *((PULONG)"0000");
|
|
LengthString[0] += (CHAR)((Length / 10000) % 10);
|
|
LengthString[1] += (CHAR)((Length / 1000) % 10);
|
|
LengthString[2] += (CHAR)((Length / 100) % 10);
|
|
LengthString[3] += (CHAR)((Length / 10) % 10);
|
|
LengthString[4] = (CHAR)('0' + (Length / 1) % 10);
|
|
LengthString[5] = ANSI_NULL;
|
|
return 5;
|
|
}
|
|
else
|
|
if (Length >= 1000)
|
|
{
|
|
*((PULONG)LengthString) = *((PULONG)"0000");
|
|
LengthString[0] += (CHAR)((Length / 1000) % 10);
|
|
LengthString[1] += (CHAR)((Length / 100) % 10);
|
|
LengthString[2] += (CHAR)((Length / 10) % 10);
|
|
LengthString[3] += (CHAR)((Length / 1) % 10);
|
|
LengthString[4] = ANSI_NULL;
|
|
return 4;
|
|
}
|
|
else
|
|
if (Length >= 100)
|
|
{
|
|
*((PULONG)LengthString) = *((PULONG)"0000");
|
|
LengthString[0] += (CHAR)((Length / 100) % 10);
|
|
LengthString[1] += (CHAR)((Length / 10) % 10);
|
|
LengthString[2] += (CHAR)((Length / 1) % 10);
|
|
LengthString[3] = ANSI_NULL;
|
|
return 3;
|
|
}
|
|
else
|
|
if (Length >= 10)
|
|
{
|
|
*((PUSHORT)LengthString) = *((PUSHORT)"00");
|
|
LengthString[0] += (CHAR)((Length / 10) % 10);
|
|
LengthString[1] += (CHAR)((Length / 1) % 10);
|
|
LengthString[2] = ANSI_NULL;
|
|
return 2;
|
|
}
|
|
else
|
|
{
|
|
LengthString[0] = (CHAR)('0' + (Length / 1) % 10);
|
|
LengthString[1] = ANSI_NULL;
|
|
return 1;
|
|
}
|
|
} // UlpFastGenerateContentLength
|
|
|
|
|
|
//
|
|
// An inline function to ProbeForRead the header portions of the HTTP_RESPONSE.
|
|
//
|
|
|
|
#define UL_MAX_HTTP_STATUS_CODE 999
|
|
|
|
__inline
|
|
NTSTATUS
|
|
FASTCALL
|
|
UlProbeHttpHeaders(
|
|
IN PHTTP_RESPONSE pUserResponse
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
PHTTP_UNKNOWN_HEADER pUnknownHeaders;
|
|
USHORT Length;
|
|
LONG i;
|
|
|
|
Status = STATUS_SUCCESS;
|
|
|
|
if (pUserResponse == NULL)
|
|
{
|
|
return Status;
|
|
}
|
|
|
|
__try
|
|
{
|
|
//
|
|
// Check flags and status code.
|
|
//
|
|
|
|
if ((pUserResponse->Flags & ~HTTP_RESPONSE_FLAG_VALID) ||
|
|
(pUserResponse->StatusCode > UL_MAX_HTTP_STATUS_CODE))
|
|
{
|
|
ExRaiseStatus( STATUS_INVALID_PARAMETER );
|
|
}
|
|
|
|
//
|
|
// Check the response structure.
|
|
//
|
|
|
|
ProbeTestForRead(
|
|
pUserResponse,
|
|
sizeof(HTTP_RESPONSE),
|
|
sizeof(USHORT)
|
|
);
|
|
|
|
//
|
|
// Check the reason string.
|
|
//
|
|
|
|
ProbeTestForRead(
|
|
pUserResponse->pReason,
|
|
pUserResponse->ReasonLength,
|
|
sizeof(CHAR)
|
|
);
|
|
|
|
//
|
|
// Loop through the known headers.
|
|
//
|
|
|
|
for (i = 0; i < HttpHeaderResponseMaximum; i++)
|
|
{
|
|
Length = pUserResponse->Headers.pKnownHeaders[i].RawValueLength;
|
|
|
|
if (Length > 0)
|
|
{
|
|
ProbeTestForRead(
|
|
pUserResponse->Headers.pKnownHeaders[i].pRawValue,
|
|
Length,
|
|
sizeof(CHAR)
|
|
);
|
|
}
|
|
}
|
|
|
|
//
|
|
// And the unknown headers (this might throw an exception).
|
|
//
|
|
|
|
pUnknownHeaders = pUserResponse->Headers.pUnknownHeaders;
|
|
|
|
if (pUnknownHeaders != NULL)
|
|
{
|
|
ProbeTestForRead(
|
|
pUnknownHeaders,
|
|
sizeof(HTTP_UNKNOWN_HEADER) * pUserResponse->Headers.UnknownHeaderCount,
|
|
sizeof(ULONG)
|
|
);
|
|
|
|
for (i = 0; i < (LONG)(pUserResponse->Headers.UnknownHeaderCount); i++)
|
|
{
|
|
if (pUnknownHeaders[i].NameLength > 0)
|
|
{
|
|
ProbeTestForRead(
|
|
pUnknownHeaders[i].pName,
|
|
pUnknownHeaders[i].NameLength,
|
|
sizeof(CHAR)
|
|
);
|
|
|
|
ProbeTestForRead(
|
|
pUnknownHeaders[i].pRawValue,
|
|
pUnknownHeaders[i].RawValueLength,
|
|
sizeof(CHAR)
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
UlTrace(IOCTL,
|
|
("UlProbeHttpHeaders validated the headers: %x\n", Status));
|
|
}
|
|
__except( UL_EXCEPTION_FILTER() )
|
|
{
|
|
Status = UL_CONVERT_EXCEPTION_CODE(GetExceptionCode());
|
|
UlTrace(IOCTL,
|
|
("UlProbeHttpHeaders caught an exception: %x\n", Status));
|
|
}
|
|
|
|
return Status;
|
|
} // UlProbeHttpHeaders
|
|
|
|
|
|
#ifdef __cplusplus
|
|
}; // extern "C"
|
|
#endif
|
|
|
|
#endif // _FASTIO_H_
|
|
|