/*++ Copyright (c) 1998-2002 Microsoft Corporation Module Name: sendrequest.h Abstract: This module contains declarations for manipulating HTTP requests. Author: Rajesh Sundaram (rajeshsu) Revision History: --*/ #ifndef _SENDREQUEST_H_ #define _SENDREQUEST_H_ // // Size of the lookaside for the send-request structure. // #define UC_REQUEST_LOOKASIDE_SIZE (sizeof(UC_HTTP_REQUEST)+1024) // // It takes 2 cycles per byte to RtlCopyMemory. It takes 1024 cycles to // ProbeLock and 1024 cycles to ProbeUnLock. So, as a rule, it is always // cheaper to copy if the BufferSize is < 2048. // #define UC_REQUEST_COPY_THRESHOLD (PAGE_SIZE/2) #define UC_REQUEST_HEADER_CHUNK_COUNT 1 // // We allow the user to specify the chunk using a ULONG. So, the maximum chunk // size is FFFFFFFF . We add another CRLF for terminating the data. // #define UC_MAX_CHUNK_SIZE (10 + 2 * CRLF_SIZE) #define MULTIPART_SEPARATOR_SIZE 80 // // Forwarders. // typedef struct _UC_HTTP_REQUEST *PUC_HTTP_REQUEST; typedef struct _UC_PROCESS_SERVER_INFORMATION *PUC_PROCESS_SERVER_INFORMATION; typedef struct _UC_CLIENT_CONNECTION *PUC_CLIENT_CONNECTION; // // This structure is used to store a parsed HTTP response. // #define UC_RESPONSE_EXTRA_BUFFER 1024 #define UC_INSUFFICIENT_INDICATION_EXTRA_BUFFER 1024 typedef struct _UC_RESPONSE_BUFFER { ULONG Signature; LIST_ENTRY Linkage; ULONG Flags; ULONG BytesWritten; ULONG BytesAllocated; HTTP_RESPONSE HttpResponse; } UC_RESPONSE_BUFFER, *PUC_RESPONSE_BUFFER; #define UC_RESPONSE_BUFFER_SIGNATURE MAKE_SIGNATURE('UcRB') #define IS_VALID_UC_RESPONSE_BUFFER(pBuffer) \ HAS_VALID_SIGNATURE(pBuffer, UC_RESPONSE_BUFFER_SIGNATURE) // // Flags definition for UC_RESPONSE_BUFFER.Flags // #define UC_RESPONSE_BUFFER_FLAG_READY 0x00000001 #define UC_RESPONSE_BUFFER_FLAG_NOT_MERGEABLE 0x00000002 typedef enum _UC_RESPONSE_PARSER { UcParseStatusLineVersion, UcParseStatusLineStatusCode, UcParseStatusLineReasonPhrase, UcParseHeaders, UcParseEntityBody, UcParseTrailers, UcParseEntityBodyMultipartInit, UcParseEntityBodyMultipartHeaders, UcParseEntityBodyMultipartFinal, UcParseError, UcParseDone } UC_RESPONSE_PARSER_STATE, *PUC_RESPONSE_PARSER_STATE; typedef enum _UC_REQUEST_STATE { UcRequestStateCaptured, // has been captured UcRequestStateSent, // captured & sent. UcRequestStateSendCompleteNoData, // send has completed, but // haven't seen any response UcRequestStateSendCompletePartialData, // send has completed & we have // seen some response, but not all // of it. UcRequestStateNoSendCompletePartialData, // no send complete & we have seen // a portion of the response. UcRequestStateNoSendCompleteFullData, // no send complete & we have // seen all response. UcRequestStateResponseParsed, // fully parsed, send completed, // app has to post additional // receive buffers. UcRequestStateDone // app has seen all data. } UC_REQUEST_STATE, *PUC_REQUEST_STATE; // // Did we receive any response for this request? // #define UC_IS_RESPONSE_RECEIVED(pRequest) \ (pRequest->RequestState == UcRequestStateSendCompletePartialData || \ pRequest->RequestState == UcRequestStateNoSendCompletePartialData || \ pRequest->RequestState == UcRequestStateNoSendCompleteFullData || \ pRequest->RequestState == UcRequestStateResponseParsed) typedef union _UC_REQUEST_FLAGS { // // This field overlays all of the settable flags. This allows us to // update all flags in a thread-safe manner using the // UlInterlockedCompareExchange() API. // LONG Value; struct { ULONG CleanPended:1; // 00000001 ULONG RequestChunked:1; // 00000002 ULONG LastEntitySeen:1; // 00000004 ULONG ContentLengthSpecified:1; // 00000008 ULONG ReceiveBufferSpecified:1; // 00000010 ULONG RequestBuffered:1; // 00000020 ULONG CompleteIrpEarly:1; // 00000040 ULONG ContentLengthLast:1; // 00000080 ULONG PipeliningAllowed:1; // 00000100 ULONG CancelSet:1; // 00000200 ULONG NoResponseEntityBodies:1; // 00000400 ULONG ProxySslConnect:1; // 00000800 ULONG Cancelled:1; // 00001000 ULONG NoRequestEntityBodies:1; // 00002000 ULONG UsePreAuth:1; // 00004000 ULONG UseProxyPreAuth:1; // 00008000 }; } UC_REQUEST_FLAGS; #define UC_MAKE_REQUEST_FLAG_ROUTINE(name) \ __inline LONG UcMakeRequest##name##Flag() \ { \ UC_REQUEST_FLAGS flags = { 0 }; \ flags.name = 1; \ return flags.Value; \ } UC_MAKE_REQUEST_FLAG_ROUTINE( RequestChunked ); UC_MAKE_REQUEST_FLAG_ROUTINE( LastEntitySeen ); UC_MAKE_REQUEST_FLAG_ROUTINE( ContentLengthSpecified ); UC_MAKE_REQUEST_FLAG_ROUTINE( ContentLengthLast ); UC_MAKE_REQUEST_FLAG_ROUTINE( CancelSet ); UC_MAKE_REQUEST_FLAG_ROUTINE( Cancelled ); UC_MAKE_REQUEST_FLAG_ROUTINE( CleanPended ); #define UC_REQUEST_RECEIVE_READY (1L) #define UC_REQUEST_RECEIVE_BUSY (2L) #define UC_REQUEST_RECEIVE_CANCELLED (3L) typedef struct _UC_HTTP_REQUEST { ULONG Signature; LIST_ENTRY Linkage; LONG RefCount; ULONGLONG RequestContentLengthRemaining; NTSTATUS RequestStatus; UC_REQUEST_FLAGS RequestFlags; HTTP_REQUEST_ID RequestId; UL_WORK_ITEM WorkItem; // // We could be piggybacking on the applications IRP. // if this is the case, we need to restore some // parameters. // KPROCESSOR_MODE AppRequestorMode; UCHAR Pad[3]; PMDL AppMdl; PIRP RequestIRP; PIO_STACK_LOCATION RequestIRPSp; ULONG RequestIRPBytesWritten; PFILE_OBJECT pFileObject; PUC_CLIENT_CONNECTION pConnection; ULONG ConnectionIndex; // // All the MDL information. // PMDL pMdlHead; PMDL *pMdlLink; // Pointer to the head of the MDL chain. // used to easily chain MDLs. ULONG BytesBuffered; // Total # of bytes buffered in // the MDL chains. // // For holding the parsed respose. // UC_RESPONSE_PARSER_STATE ParseState; UC_REQUEST_STATE RequestState; // // The following fields hold data pertaining to the current buffer that // the parser has to write its response to. The current buffer could // either be the buffer passed by the application, or it could point to an // internally allocated buffer. // // All internally allocated buffers are stored in pBufferList. // PHTTP_RESPONSE pInternalResponse; struct { ULONG BytesAllocated; ULONG BytesAvailable; PUCHAR pOutBufferHead; // Pointer to the head of output // buffer PUCHAR pOutBufferTail; // Pointer to the tail of // output buffer PHTTP_RESPONSE pResponse; // pointer to the response // structure of current buffer PUC_RESPONSE_BUFFER pCurrentBuffer; // A pointer to the current // buffer. } CurrentBuffer; LIST_ENTRY pBufferList; // This holds a list of chained // buffers. LIST_ENTRY ReceiveResponseIrpList; BOOLEAN ResponseMultipartByteranges; BOOLEAN ResponseConnectionClose; BOOLEAN RequestConnectionClose; BOOLEAN ResponseVersion11; BOOLEAN ResponseEncodingChunked; BOOLEAN ResponseContentLengthSpecified; BOOLEAN DontFreeMdls; BOOLEAN Renegotiate; ULONGLONG ResponseContentLength; ULONG ParsedFirstChunk; SIZE_T RequestSize; LIST_ENTRY PendingEntityList; LIST_ENTRY SentEntityList; ULONG MaxHeaderLength; ULONG HeaderLength; PUCHAR pHeaders; FAST_MUTEX Mutex; PUC_HTTP_AUTH pAuthInfo; PUC_HTTP_AUTH pProxyAuthInfo; PCHAR pMultipartStringSeparator; CHAR MultipartStringSeparatorBuffer[MULTIPART_SEPARATOR_SIZE]; ULONG MultipartStringSeparatorLength; ULONG MultipartRangeRemaining; ULONG ResponseStatusCode; PUC_PROCESS_SERVER_INFORMATION pServerInfo; PSTR pUri; USHORT UriLength; LONG ReceiveBusy; } UC_HTTP_REQUEST, *PUC_HTTP_REQUEST; // // Http request can go out on any available connection. // #define HTTP_REQUEST_ON_CONNECTION_ANY (~(0UL)) typedef struct _UC_HTTP_RECEIVE_RESPONSE { LIST_ENTRY Linkage; PIRP pIrp; BOOLEAN CancelSet; PUC_HTTP_REQUEST pRequest; LIST_ENTRY ResponseBufferList; } UC_HTTP_RECEIVE_RESPONSE, *PUC_HTTP_RECEIVE_RESPONSE; typedef struct _UC_HTTP_SEND_ENTITY_BODY { ULONG Signature; LIST_ENTRY Linkage; PIRP pIrp; BOOLEAN CancelSet; BOOLEAN Last; PUC_HTTP_REQUEST pRequest; PMDL pMdlHead; PMDL *pMdlLink; ULONG BytesBuffered; KPROCESSOR_MODE AppRequestorMode; UCHAR Pad[3]; PMDL AppMdl; SIZE_T BytesAllocated; } UC_HTTP_SEND_ENTITY_BODY, *PUC_HTTP_SEND_ENTITY_BODY; #define UC_REQUEST_SIGNATURE MAKE_SIGNATURE('HREQ') #define UC_REQUEST_SIGNATURE_X MAKE_FREE_SIGNATURE(UC_REQUEST_SIGNATURE) #define UC_ENTITY_SIGNATURE MAKE_SIGNATURE('HENT') #define UC_ENTITY_SIGNATURE_X MAKE_FREE_SIGNATURE(UC_REQUEST_SIGNATURE) #define UC_IS_VALID_HTTP_REQUEST(pRequest) \ HAS_VALID_SIGNATURE(pRequest, UC_REQUEST_SIGNATURE) #define UC_REFERENCE_REQUEST(s) \ UcReferenceRequest( \ (s) \ REFERENCE_DEBUG_ACTUAL_PARAMS \ ) #define UC_DEREFERENCE_REQUEST(s) \ UcDereferenceRequest( \ (s) \ REFERENCE_DEBUG_ACTUAL_PARAMS \ ) NTSTATUS UcCaptureHttpRequest(IN PUC_PROCESS_SERVER_INFORMATION pServInfo, IN PHTTP_SEND_REQUEST_INPUT_INFO pHttpRequest, IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp, OUT PUC_HTTP_REQUEST *ppInternalRequest, IN PULONG pBytesTaken); VOID UcpProbeAndCopyHttpRequest( IN PHTTP_REQUEST pHttpRequest, IN PHTTP_REQUEST pLocalHttpRequest, IN KPROCESSOR_MODE RequestorMode ); VOID UcpRetrieveContentLength( IN PHTTP_REQUEST pHttpRequest, OUT PBOOLEAN pbContentLengthSpecified, OUT PULONGLONG pContentLength ); VOID UcpRequestInitialize( IN PUC_HTTP_REQUEST pRequest, IN SIZE_T RequestLength, IN ULONGLONG RemainingContentLength, IN PUC_HTTP_AUTH pAuth, IN PUC_HTTP_AUTH pProxyAuth, IN PUC_CLIENT_CONNECTION pConnection, IN PIRP Irp, IN PIO_STACK_LOCATION pIrpSp, IN PUC_PROCESS_SERVER_INFORMATION pServerInfo ); VOID UcpRequestCommonInitialize( IN PUC_HTTP_REQUEST pRequest, IN ULONG OutLength, IN PUCHAR pBuffer ); VOID UcpFixAppBufferPointers( PUC_HTTP_REQUEST pRequest, PIRP pIrp ); VOID UcpProbeConfigList( IN PHTTP_REQUEST_CONFIG pRequestConfig, IN USHORT RequestConfigCount, IN KPROCESSOR_MODE RequestorMode, IN PUC_PROCESS_SERVER_INFORMATION pServInfo, IN PUC_HTTP_AUTH *ppIAuth, IN PUC_HTTP_AUTH *ppIProxyAuth, IN PULONG pConnectionIndex ); VOID UcFreeSendMdls( IN PMDL pMdl ); VOID UcReferenceRequest( IN PVOID pObject REFERENCE_DEBUG_FORMAL_PARAMS ); VOID UcDereferenceRequest( IN PVOID pObject REFERENCE_DEBUG_FORMAL_PARAMS ); PIRP UcPrepareRequestIrp( IN PUC_HTTP_REQUEST pRequest, IN NTSTATUS Status ); NTSTATUS UcCompleteParsedRequest( IN PUC_HTTP_REQUEST pRequest, IN NTSTATUS Status, IN BOOLEAN NextRequest, IN KIRQL OldIrql ); BOOLEAN UcSetRequestCancelRoutine( PUC_HTTP_REQUEST pRequest, PDRIVER_CANCEL pCancelRoutine ); BOOLEAN UcRemoveRequestCancelRoutine( PUC_HTTP_REQUEST pRequest ); BOOLEAN UcSetEntityCancelRoutine( PUC_HTTP_SEND_ENTITY_BODY pEntity, PDRIVER_CANCEL pCancelRoutine ); BOOLEAN UcRemoveEntityCancelRoutine( PUC_HTTP_SEND_ENTITY_BODY pEntity ); BOOLEAN UcSetRecvResponseCancelRoutine( PUC_HTTP_RECEIVE_RESPONSE pResponse, PDRIVER_CANCEL pCancelRoutine ); BOOLEAN UcRemoveRcvRespCancelRoutine( PUC_HTTP_RECEIVE_RESPONSE pResponse ); VOID UcpFreeRequest( IN PUL_WORK_ITEM pWorkItem ); NTSTATUS UcCopyResponseToIrp( PIRP pIrp, PLIST_ENTRY pResponseBufferList, PBOOLEAN bDone, PULONG pBytesTaken ); NTSTATUS UcReceiveHttpResponse( IN PUC_HTTP_REQUEST pRequest, IN PIRP pIrp, IN PULONG pBytesTaken ); VOID UcpCancelReceiveResponse( PDEVICE_OBJECT pDeviceObject, PIRP Irp ); VOID UcpCancelSendEntity( PDEVICE_OBJECT pDeviceObject, PIRP Irp ); VOID UcpComputeEntityBodyLength( USHORT EntityChunkCount, PHTTP_DATA_CHUNK pEntityChunks, BOOLEAN bContentLengthSpecified, BOOLEAN bServer11, PULONGLONG UncopiedLength, PULONGLONG CopiedLength ); NTSTATUS UcCaptureEntityBody( PHTTP_SEND_REQUEST_ENTITY_BODY_INFO pSendInfo, PIRP Irp, PUC_HTTP_REQUEST pRequest, PUC_HTTP_SEND_ENTITY_BODY *ppKeEntity, BOOLEAN bLast ); NTSTATUS UcpBuildEntityMdls( USHORT ChunkCount, PHTTP_DATA_CHUNK pHttpEntityBody, BOOLEAN bServer11, BOOLEAN bChunked, BOOLEAN bLast, PSTR pBuffer, PMDL **pMdlLink, PULONG BytesBuffered ); NTSTATUS UcInitializeHttpRequests( VOID ); VOID UcTerminateHttpRequests( VOID ); VOID UcAllocateAndChainHeaderMdl( IN PUC_HTTP_REQUEST pRequest ); VOID UcpAllocateAndChainEntityMdl( IN PVOID pMdlBuffer, IN ULONG MdlLength, IN PMDL **pMdlLink, IN PULONG BytesBuffered ); PUC_HTTP_REQUEST UcBuildConnectVerbRequest( IN PUC_CLIENT_CONNECTION pConnection, IN PUC_HTTP_REQUEST pHeadRequest ); VOID UcFailRequest( IN PUC_HTTP_REQUEST pRequest, IN NTSTATUS Status, IN KIRQL OldIrql ); VOID UcReIssueRequestWorker( IN PUL_WORK_ITEM pWorkItem ); VOID UcpProbeAndCopyEntityChunks( IN KPROCESSOR_MODE RequestorMode, IN PHTTP_DATA_CHUNK pEntityChunks, IN ULONG EntityChunkCount, IN PHTTP_DATA_CHUNK pLocalEntityChunksArray, OUT PHTTP_DATA_CHUNK *ppLocalEntityChunks ); #define IS_MDL_LOCKED(pmdl) (((pmdl)->MdlFlags & MDL_PAGES_LOCKED) != 0) NTSTATUS UcFindBuffersForReceiveResponseIrp( IN PUC_HTTP_REQUEST pRequest, IN ULONG OutBufferLen, IN BOOLEAN bForceComplete, OUT PLIST_ENTRY pResponseBufferList, OUT PULONG pTotalBytes ); VOID UcpPreAuthWorker( IN PUL_WORK_ITEM pWorkItem ); __inline BOOLEAN UcpCheckForPreAuth( IN PUC_HTTP_REQUEST pRequest ); __inline BOOLEAN UcpCheckForProxyPreAuth( IN PUC_HTTP_REQUEST pRequest ); #endif