public HttpListenerContext GetContext()
{
if (NetEventSource.IsEnabled) NetEventSource.Enter(this);
SyncRequestContext memoryBlob = null;
HttpListenerContext httpContext = null;
bool stoleBlob = false;
try
{
CheckDisposed();
if (_state == State.Stopped)
{
throw new InvalidOperationException(SR.Format(SR.net_listener_mustcall, "Start()"));
}
if (_uriPrefixes.Count == 0)
{
throw new InvalidOperationException(SR.Format(SR.net_listener_mustcall, "AddPrefix()"));
}
uint statusCode = Interop.HttpApi.ERROR_SUCCESS;
uint size = 4096;
ulong requestId = 0;
memoryBlob = new SyncRequestContext((int)size);
for (;;)
{
for (;;)
{
if (NetEventSource.IsEnabled) NetEventSource.Info(this, $"Calling Interop.HttpApi.HttpReceiveHttpRequest RequestId: {requestId}");
uint bytesTransferred = 0;
statusCode =
Interop.HttpApi.HttpReceiveHttpRequest(
_requestQueueHandle,
requestId,
(uint)Interop.HttpApi.HTTP_FLAGS.HTTP_RECEIVE_REQUEST_FLAG_COPY_BODY,
memoryBlob.RequestBlob,
size,
&bytesTransferred,
null);
if (NetEventSource.IsEnabled) NetEventSource.Info(this, "Call to Interop.HttpApi.HttpReceiveHttpRequest returned:" + statusCode);
if (statusCode == Interop.HttpApi.ERROR_INVALID_PARAMETER && requestId != 0)
{
// we might get this if somebody stole our RequestId,
// we need to start all over again but we can reuse the buffer we just allocated
requestId = 0;
continue;
}
else if (statusCode == Interop.HttpApi.ERROR_MORE_DATA)
{
// the buffer was not big enough to fit the headers, we need
// to read the RequestId returned, allocate a new buffer of the required size
size = bytesTransferred;
requestId = memoryBlob.RequestBlob->RequestId;
memoryBlob.Reset(checked((int)size));
continue;
}
break;
}
if (statusCode != Interop.HttpApi.ERROR_SUCCESS)
{
// someother bad error, return values are:
// ERROR_INVALID_HANDLE, ERROR_INSUFFICIENT_BUFFER, ERROR_OPERATION_ABORTED
throw new HttpListenerException((int)statusCode);
}
if (ValidateRequest(memoryBlob))
{
// We need to hook up our authentication handling code here.
httpContext = HandleAuthentication(memoryBlob, out stoleBlob);
}
if (stoleBlob)
{
// The request has been handed to the user, which means this code can't reuse the blob. Reset it here.
memoryBlob = null;
stoleBlob = false;
}
if (NetEventSource.IsEnabled) NetEventSource.Info(this, ":HandleAuthentication() returned httpContext" + httpContext);
// if the request survived authentication, return it to the user
if (httpContext != null)
{
return httpContext;
}
// HandleAuthentication may have cleaned this up.
if (memoryBlob == null)
{
memoryBlob = new SyncRequestContext(checked((int)size));
}
requestId = 0;
}
}
catch (Exception exception)
{
if (NetEventSource.IsEnabled) NetEventSource.Error(this, $"{exception}");
throw;
}
finally
{
if (memoryBlob != null && !stoleBlob)
{
memoryBlob.ReleasePins();
memoryBlob.Close();
}
if (NetEventSource.IsEnabled) NetEventSource.Exit(this, "RequestTraceIdentifier: " + (httpContext != null ? httpContext.Request.RequestTraceIdentifier.ToString() : "<null>"));
}
}