170 lines
6.0 KiB
C#
170 lines
6.0 KiB
C#
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Microsoft Research Singularity
|
||
|
//
|
||
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||
|
//
|
||
|
// File: RemoteHttpRequest.sg
|
||
|
//
|
||
|
// Note:
|
||
|
// This file wraps a cassini Request object so it is callable through
|
||
|
// the Microsoft.Singularity.WebApps.IHttpRequest interface that web
|
||
|
// applications understand.
|
||
|
// regular object.
|
||
|
//
|
||
|
|
||
|
using System;
|
||
|
using Microsoft.SingSharp;
|
||
|
using Microsoft.SingSharp.Runtime;
|
||
|
using Microsoft.Singularity;
|
||
|
using Microsoft.Singularity.Channels;
|
||
|
using Microsoft.Singularity.WebApps;
|
||
|
using System.Web;
|
||
|
using System.Threading;
|
||
|
|
||
|
namespace Microsoft.VisualStudio.WebHost
|
||
|
{
|
||
|
internal class LocalHttpRequest : IHttpRequest
|
||
|
{
|
||
|
private Request m_Req;
|
||
|
private byte[] cachedBodyData = null;
|
||
|
private Mutex bodyDataMutex = new Mutex();
|
||
|
|
||
|
internal LocalHttpRequest(Request request)
|
||
|
{
|
||
|
m_Req = request;
|
||
|
}
|
||
|
|
||
|
public string! GetUriPath()
|
||
|
{ return (!)m_Req.GetUriPath(); }
|
||
|
|
||
|
public string GetQueryString()
|
||
|
{ return m_Req.GetQueryString(); }
|
||
|
|
||
|
public string GetVerb()
|
||
|
{ return m_Req.GetHttpVerbName(); }
|
||
|
|
||
|
public string GetHeader(string! headerName)
|
||
|
{
|
||
|
int knownIndex = HttpWorkerRequest.GetKnownRequestHeaderIndex(headerName);
|
||
|
|
||
|
if (knownIndex > 0) {
|
||
|
return m_Req.GetKnownRequestHeader(knownIndex);
|
||
|
} else {
|
||
|
return m_Req.GetUnknownRequestHeader(headerName);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public string! GetRemoteAddress()
|
||
|
{ return m_Req.GetRemoteAddress(); }
|
||
|
|
||
|
// Caller should not modify this buffer!
|
||
|
public byte[] GetBodyData()
|
||
|
{
|
||
|
if (m_Req.IsEntireEntityBodyIsPreloaded()) {
|
||
|
// Return a copy of the preloaded body and trust the
|
||
|
// caller not to monkey with it.
|
||
|
return m_Req.GetPreloadedEntityBody();
|
||
|
} else {
|
||
|
|
||
|
int totalBodyLength = m_Req.GetTotalEntityBodyLength();
|
||
|
|
||
|
if (totalBodyLength == 0) {
|
||
|
return null; // No body expected at all
|
||
|
}
|
||
|
// Else there is body data that wasn't received as part of
|
||
|
// the initial request.
|
||
|
|
||
|
if (cachedBodyData == null) {
|
||
|
try {
|
||
|
bodyDataMutex.AcquireMutex();
|
||
|
|
||
|
if (cachedBodyData != null) {
|
||
|
// Someone loaded this concurrently to us
|
||
|
return cachedBodyData;
|
||
|
}
|
||
|
|
||
|
byte[] preloadedBody = m_Req.GetPreloadedEntityBody();
|
||
|
int preloadedLength = m_Req.GetPreloadedEntityBodyLength();
|
||
|
byte[] body = new byte[totalBodyLength];
|
||
|
|
||
|
if ((preloadedLength > 0) && (preloadedBody != null)) {
|
||
|
// First copy the cached portion
|
||
|
Buffer.BlockCopy(preloadedBody, 0,
|
||
|
body, 0, preloadedLength);
|
||
|
} else {
|
||
|
assert ((preloadedBody == null) && (preloadedLength == 0));
|
||
|
}
|
||
|
|
||
|
// Now read in any remainder
|
||
|
int remainder = totalBodyLength - preloadedLength;
|
||
|
assert remainder > 0; // Tested earlier
|
||
|
|
||
|
while (remainder > 0) {
|
||
|
int readBytes = m_Req.ReadEntityBody(body, totalBodyLength - remainder,
|
||
|
remainder);
|
||
|
|
||
|
if (readBytes == 0) {
|
||
|
// Body wasn't as long as we were expecting for some
|
||
|
// reason! This could be because the remote client
|
||
|
// lied to us in the headers. Truncate the cached
|
||
|
// data to the actual body size.
|
||
|
byte[] shortBody = new byte[totalBodyLength - remainder];
|
||
|
Array.Copy(body, 0, shortBody, 0, totalBodyLength - remainder);
|
||
|
body = shortBody;
|
||
|
remainder = 0; // No more data will be forthcoming
|
||
|
} else {
|
||
|
remainder -= readBytes;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Stash this for other callers
|
||
|
cachedBodyData = body;
|
||
|
}
|
||
|
finally {
|
||
|
bodyDataMutex.ReleaseMutex();
|
||
|
}
|
||
|
}
|
||
|
// else we previously cached the body data.
|
||
|
|
||
|
return cachedBodyData;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public void SendStatus(int code, string! description)
|
||
|
{ m_Req.SendStatus(code, description); }
|
||
|
|
||
|
public void SendHeader(string! name, string! value)
|
||
|
{
|
||
|
int index = HttpWorkerRequest.GetKnownResponseHeaderIndex(name);
|
||
|
|
||
|
if (index == -1)
|
||
|
{
|
||
|
m_Req.SendUnknownResponseHeader(name, value);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
m_Req.SendKnownResponseHeader(index, value);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public void SendBodyData(byte[]! data)
|
||
|
{
|
||
|
m_Req.SendResponseFromMemory(data, data.Length);
|
||
|
m_Req.FlushResponse(false); // always transmit immediately
|
||
|
}
|
||
|
|
||
|
public void SendBodyData([Claims] byte[]! in ExHeap data)
|
||
|
{
|
||
|
m_Req.SendResponseFromMemory(data);
|
||
|
m_Req.FlushResponse(false); // always transmit immediately
|
||
|
}
|
||
|
|
||
|
public void Done()
|
||
|
{
|
||
|
m_Req.FlushResponse(true);
|
||
|
m_Req.EndOfRequest();
|
||
|
}
|
||
|
}
|
||
|
}
|