////////////////////////////////////////////////////////////////////////////////
//
// Microsoft Research Singularity
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// File: WorkerRequest.cs
//
// Note:
// This module defines the base worker class used by ASP.NET Managed
// code for request processing.
//
// This file was ported, from the Coriolis codebase to Singularity by Mark Aiken.
//
namespace System.Web {
using System.Text;
using System.Collections;
using System.Web.Hosting;
using System.Web.Util;
public abstract class HttpWorkerRequest {
private DateTime _startTime;
public HttpWorkerRequest()
{
_startTime = DateTime.UtcNow;
}
// ************************************************************************
//
// Indexed Headers. All headers that are defined by HTTP/1.1. These
// values are used as offsets into arrays and as token values.
//
// IMPORTANT : Notice request + response values overlap. Make sure you
// know which type of header array you are indexing.
//
//
// general-headers [section 4.5]
//
//|
///
/// [To be supplied.]
///
public const int HeaderCacheControl = 0;
//|
///
/// [To be supplied.]
///
public const int HeaderConnection = 1;
//|
///
/// [To be supplied.]
///
public const int HeaderDate = 2;
//|
///
/// [To be supplied.]
///
public const int HeaderKeepAlive = 3; // not in rfc
//|
///
/// [To be supplied.]
///
public const int HeaderPragma = 4;
//|
///
/// [To be supplied.]
///
public const int HeaderTrailer = 5;
//|
///
/// [To be supplied.]
///
public const int HeaderTransferEncoding = 6;
//|
///
/// [To be supplied.]
///
public const int HeaderUpgrade = 7;
//|
///
/// [To be supplied.]
///
public const int HeaderVia = 8;
//|
///
/// [To be supplied.]
///
public const int HeaderWarning = 9;
//
// entity-headers [section 7.1]
//
//|
///
/// [To be supplied.]
///
public const int HeaderAllow = 10;
//|
///
/// [To be supplied.]
///
public const int HeaderContentLength = 11;
//|
///
/// [To be supplied.]
///
public const int HeaderContentType = 12;
//|
///
/// [To be supplied.]
///
public const int HeaderContentEncoding = 13;
//|
///
/// [To be supplied.]
///
public const int HeaderContentLanguage = 14;
//|
///
/// [To be supplied.]
///
public const int HeaderContentLocation = 15;
//|
///
/// [To be supplied.]
///
public const int HeaderContentMd5 = 16;
//|
///
/// [To be supplied.]
///
public const int HeaderContentRange = 17;
//|
///
/// [To be supplied.]
///
public const int HeaderExpires = 18;
//|
///
/// [To be supplied.]
///
public const int HeaderLastModified = 19;
//
// request-headers [section 5.3]
//
//|
///
/// [To be supplied.]
///
public const int HeaderAccept = 20;
//|
///
/// [To be supplied.]
///
public const int HeaderAcceptCharset = 21;
//|
///
/// [To be supplied.]
///
public const int HeaderAcceptEncoding = 22;
//|
///
/// [To be supplied.]
///
public const int HeaderAcceptLanguage = 23;
//|
///
/// [To be supplied.]
///
public const int HeaderAuthorization = 24;
//|
///
/// [To be supplied.]
///
public const int HeaderCookie = 25; // not in rfc
//|
///
/// [To be supplied.]
///
public const int HeaderExpect = 26;
//|
///
/// [To be supplied.]
///
public const int HeaderFrom = 27;
//|
///
/// [To be supplied.]
///
public const int HeaderHost = 28;
//|
///
/// [To be supplied.]
///
public const int HeaderIfMatch = 29;
//|
///
/// [To be supplied.]
///
public const int HeaderIfModifiedSince = 30;
//|
///
/// [To be supplied.]
///
public const int HeaderIfNoneMatch = 31;
//|
///
/// [To be supplied.]
///
public const int HeaderIfRange = 32;
//|
///
/// [To be supplied.]
///
public const int HeaderIfUnmodifiedSince = 33;
//|
///
/// [To be supplied.]
///
public const int HeaderMaxForwards = 34;
//|
///
/// [To be supplied.]
///
public const int HeaderProxyAuthorization = 35;
//|
///
/// [To be supplied.]
///
public const int HeaderReferer = 36;
//|
///
/// [To be supplied.]
///
public const int HeaderRange = 37;
//|
///
/// [To be supplied.]
///
public const int HeaderTe = 38;
//|
///
/// [To be supplied.]
///
public const int HeaderUserAgent = 39;
//
// Request headers end here
//
//|
///
/// [To be supplied.]
///
public const int RequestHeaderMaximum = 40;
//
// response-headers [section 6.2]
//
//|
///
/// [To be supplied.]
///
public const int HeaderAcceptRanges = 20;
//|
///
/// [To be supplied.]
///
public const int HeaderAge = 21;
//|
///
/// [To be supplied.]
///
public const int HeaderEtag = 22;
//|
///
/// [To be supplied.]
///
public const int HeaderLocation = 23;
//|
///
/// [To be supplied.]
///
public const int HeaderProxyAuthenticate = 24;
//|
///
/// [To be supplied.]
///
public const int HeaderRetryAfter = 25;
//|
///
/// [To be supplied.]
///
public const int HeaderServer = 26;
//|
///
/// [To be supplied.]
///
public const int HeaderSetCookie = 27; // not in rfc
//|
///
/// [To be supplied.]
///
public const int HeaderVary = 28;
//|
///
/// [To be supplied.]
///
public const int HeaderWwwAuthenticate = 29;
//
// Response headers end here
//
//|
///
/// [To be supplied.]
///
public const int ResponseHeaderMaximum = 30;
// ************************************************************************
//
// Request reasons
//
//|
///
/// [To be supplied.]
///
///
public const int ReasonResponseCacheMiss = 0;
//|
///
/// [To be supplied.]
///
///
public const int ReasonFileHandleCacheMiss = 1;
//|
///
/// [To be supplied.]
///
///
public const int ReasonCachePolicy = 2;
//|
///
/// [To be supplied.]
///
///
public const int ReasonCacheSecurity = 3;
//|
///
/// [To be supplied.]
///
///
public const int ReasonClientDisconnect = 4;
//|
///
/// [To be supplied.]
///
///
public const int ReasonDefault = ReasonResponseCacheMiss;
// ************************************************************************
//
// Access to request related members
//
// required members
//|
///
/// Returns the physical path to the requested Uri.
///
public abstract String GetUriPath(); // "/foo/page.aspx/tail"
//|
///
/// Provides Access to the specified member of the request header.
///
public abstract String GetQueryString(); // "param=bar"
//|
///
/// Provides Access to the specified member of the request header.
///
public abstract String GetRawUrl(); // "/foo/page.aspx/tail?param=bar"
//|
///
/// Provides Access to the specified member of the request header.
///
public abstract String GetHttpVerbName(); // "GET"
//|
///
/// Provides Access to the specified member of the request header.
///
public abstract String GetHttpVersion(); // "HTTP/1.1"
//|
///
/// Provides Access to the specified member of the request header.
///
public abstract String GetRemoteAddress(); // client's ip address
//|
///
/// Provides Access to the specified member of the request header.
///
public abstract int GetRemotePort(); // client's port
//|
///
/// Provides Access to the specified member of the request header.
///
public abstract String GetLocalAddress(); // server's ip address
//|
///
/// Provides Access to the specified member of the request header.
///
public abstract int GetLocalPort(); // server's port
// optional members with defaults supplied
//|
///
/// When overridden in a derived class, returns the response query string as an array of bytes.
///
public virtual byte[] GetQueryStringRawBytes() {
// access to raw qs for i18n
return null;
}
//|
///
/// When overridden in a derived class, returns the client computer's name.
///
public virtual String GetRemoteName() {
// client's name
return GetRemoteAddress();
}
//|
///
/// When overridden in a derived class, returns the name of the local server.
///
public virtual String GetServerName() {
// server's name
return GetLocalAddress();
}
//|
///
/// When overridden in a derived class, returns the ID of the current connection.
///
///
public virtual long GetConnectionID() {
// connection id
return 0;
}
//|
///
/// When overridden in a derived class, returns the context ID of the current connection.
///
///
public virtual long GetUrlContextID() {
// UL APPID
return 0;
}
//|
///
/// When overridden in a derived class, returns the application pool ID for the current URL.
///
///
public virtual String GetAppPoolID() {
// UL Application pool id
return null;
}
//|
///
/// When overridden in a derived class, returns the reason for the request.
///
///
public virtual int GetRequestReason() {
// constants Reason... above
return ReasonDefault;
}
//|
///
/// When overridden in a derived class, returns the client's impersonation token.
///
public virtual IntPtr GetUserToken() {
// impersonation token
return IntPtr.Zero;
}
//|
///
public virtual IntPtr GetVirtualPathToken() {
// impersonation token
return IntPtr.Zero;
}
//|
///
/// When overridden in a derived class, returns a value indicating whether the connection is secure (using SSL).
///
public virtual bool IsSecure() {
// is over ssl?
return false;
}
//|
///
/// When overridden in a derived class, returns the HTTP protocol (HTTP or HTTPS).
///
public virtual String GetProtocol() {
return IsSecure() ? "https" : "http";
}
//|
///
/// When overridden in a derived class, returns the physical path to the requested Uri.
///
public virtual String GetFilePath() {
// "/foo/page.aspx"
return GetUriPath();
}
//|
///
/// When overridden in a derived class, returns the translated file path to the requested Uri (from virtual path to
/// UNC path, ie "/foo/page.aspx" to "c:\dir\page.aspx")
///
public virtual String GetFilePathTranslated() {
// "c:\dir\page.aspx"
return null;
}
//|
///
/// When overridden in a derived class, returns additional
/// path information for a resource with a URL extension. i.e. for the URL
/// /virdir/page.html/tail, the PathInfo value is /tail.
///
public virtual String GetPathInfo() {
// "/tail"
return "";
}
//|
///
/// When overridden in a derived class, returns the virtual path to the
/// currently executing server application.
///
public virtual String GetAppPath() {
// "/foo"
return null;
}
//|
///
/// When overridden in a derived class, returns the UNC-translated path to
/// the currently executing server application.
///
public virtual String GetAppPathTranslated() {
// "c:\dir"
return null;
}
//
// Virtual methods to read the incoming request
//
public virtual int GetPreloadedEntityBodyLength() {
byte[] bytes = GetPreloadedEntityBody();
return (bytes != null) ? bytes.Length : 0;
}
public virtual int GetPreloadedEntityBody(byte[] buffer, int offset) {
int l = 0;
byte[] bytes = GetPreloadedEntityBody();
if (bytes != null) {
l = bytes.Length;
Buffer.BlockCopy(bytes, 0, buffer, offset, l);
}
return l;
}
public virtual byte[] GetPreloadedEntityBody() {
return null;
}
[Microsoft.Contracts.Pure]
public virtual bool IsEntireEntityBodyIsPreloaded() {
return false;
}
public virtual int GetTotalEntityBodyLength() {
int l = 0;
String contentLength = GetKnownRequestHeader(HeaderContentLength);
if (contentLength != null) {
try {
l = Int32.Parse(contentLength);
}
catch {
}
}
return l;
}
public virtual int ReadEntityBody(byte[] buffer, int size) {
return 0;
}
public virtual int ReadEntityBody(byte[] buffer, int offset, int size) {
byte[] temp = new byte[size];
int l = ReadEntityBody(temp, size);
if (l > 0) {
Buffer.BlockCopy(temp, 0, buffer, offset, l);
}
return l;
}
//|
///
/// [To be supplied.]
///
public virtual String GetKnownRequestHeader(int index) {
return null;
}
//|
///
/// [To be supplied.]
///
public virtual String GetUnknownRequestHeader(String name) {
return null;
}
//|
///
/// [To be supplied.]
///
[CLSCompliant(false)]
public virtual String[][] GetUnknownRequestHeaders() {
return null;
}
//|
///
/// [To be supplied.]
///
public virtual String GetServerVariable(String name) {
return null;
}
//|
///
/// [To be supplied.]
///
///
public virtual long GetBytesRead() {
return 0;
}
//|
///
/// [To be supplied.]
///
///
internal virtual DateTime GetStartTime() {
return _startTime;
}
//|
///
/// [To be supplied.]
///
///
internal virtual void ResetStartTime() {
_startTime = DateTime.UtcNow;
}
//|
///
/// [To be supplied.]
///
public virtual String MapPath(String virtualPath) {
return null;
}
//|
///
/// [To be supplied.]
///
public virtual String MachineConfigPath {
get {
return null;
}
}
#if ORCAS
//|
///
/// [To be supplied.]
///
public virtual String ApplicationServerConfigPath {
get {
return null;
}
}
#endif
//|
///
/// [To be supplied.]
///
public virtual String MachineInstallDirectory {
get {
return null;
}
}
//
// Abstract methods to write the response
//
//|
///
/// [To be supplied.]
///
public abstract void SendStatus(int statusCode, String statusDescription);
//|
///
/// [To be supplied.]
///
public abstract void SendKnownResponseHeader(int index, String value);
//|
///
/// [To be supplied.]
///
public abstract void SendUnknownResponseHeader(String name, String value);
// headers encoding controlled via HttpResponse.HeaderEncoding
internal virtual void SetHeaderEncoding(Encoding encoding) {
}
//|
///
/// [To be supplied.]
///
public abstract void SendResponseFromMemory(byte[] data, int length);
//|
///
/// [To be supplied.]
///
public abstract void SendResponseFromFile(String filename, long offset, long length);
//|
///
/// [To be supplied.]
///
public abstract void SendResponseFromFile(IntPtr handle, long offset, long length);
internal virtual void TransmitFile(String filename, long length, bool isImpersonating) {
TransmitFile(filename, 0, length, isImpersonating);
}
internal virtual void TransmitFile(String filename, long offset, long length, bool isImpersonating) {
// default implementation
SendResponseFromFile(filename, offset, length);
}
internal virtual void TransmitFile(IntPtr fileHandle, long offset, long length) {
// default implementation
SendResponseFromFile(fileHandle, offset, length);
}
// Execute Url
internal virtual bool SupportsExecuteUrl {
get { return false; }
}
internal virtual IAsyncResult BeginExecuteUrl(
String url, String method, String headers,
bool sendHeaders,
bool addUserIndo, IntPtr token, String name, String authType,
AsyncCallback cb, Object @state) {
throw new NotSupportedException();
}
internal virtual void EndExecuteUrl(IAsyncResult result) {
}
//|
///
/// [To be supplied.]
///
public abstract void FlushResponse(bool finalFlush);
//|
///
/// [To be supplied.]
///
public abstract void EndOfRequest();
//
// Virtual helper methods
//
//|
///
/// [To be supplied.]
///
public delegate void EndOfSendNotification(HttpWorkerRequest wr, Object extraData);
//|
///
/// [To be supplied.]
///
public virtual void SetEndOfSendNotification(EndOfSendNotification callback, Object extraData) {
// firing the callback helps with buffer recycling
}
//|
///
/// [To be supplied.]
///
public virtual void SendCalculatedContentLength(int contentLength) {
// opportunity to add Content-Length header if not added by user
}
//|
///
/// [To be supplied.]
///
public virtual bool HeadersSent() {
return true;
}
//|
///
/// [To be supplied.]
///
public virtual bool IsClientConnected() {
return true;
}
//|
///
/// [To be supplied.]
///
public virtual void CloseConnection() {
}
//|
///
/// Defines the base worker class used by ASP.NET Managed code for request
/// processing.
///
///
public virtual byte [] GetClientCertificate() {
return new byte[0];
}
//|
///
/// [To be supplied.]
///
///
public virtual DateTime GetClientCertificateValidFrom() {
return DateTime.Now;
}
//|
///
/// [To be supplied.]
///
///
public virtual DateTime GetClientCertificateValidUntil() {
return DateTime.Now;
}
//|
///
/// [To be supplied.]
///
///
public virtual byte [] GetClientCertificateBinaryIssuer() {
return new byte[0];
}
//|
///
/// [To be supplied.]
///
///
public virtual int GetClientCertificateEncoding() {
return 0;
}
//|
///
/// [To be supplied.]
///
///
public virtual byte[] GetClientCertificatePublicKey() {
return new byte[0];
}
// ************************************************************************
//
// criteria to find out if there is posted data
//
//|
///
/// [To be supplied.]
///
public bool HasEntityBody() {
//
// content length != 0 -> assume has content
//
String contentLength = GetKnownRequestHeader(HeaderContentLength);
if (contentLength != null && !contentLength.Equals("0"))
return true;
//
// any content encoding -> assume has content
//
if (GetKnownRequestHeader(HeaderTransferEncoding) != null)
return true;
//
// preloaded -> has it
//
if (GetPreloadedEntityBody() != null)
return true;
//
// no posted data but everything preloaded -> no content
//
if (IsEntireEntityBodyIsPreloaded())
return false;
return false;
}
// ************************************************************************
//
// Default values for Http status description strings
//
//|
///
/// [To be supplied.]
///
public static String GetStatusDescription(int code) {
if (code >= 100 && code < 600) {
int i = code / 100;
int j = code % 100;
if (j < s_HTTPStatusDescriptions[i].Length)
return s_HTTPStatusDescriptions[i][j];
}
return "";
}
// Tables of status strings (first index is code/100, 2nd code%100)
private static readonly String[][] s_HTTPStatusDescriptions = new String[][]
{
null,
new String[]
{
/* 100 */"Continue",
/* 101 */ "Switching Protocols",
/* 102 */ "Processing"
},
new String[]
{
/* 200 */"OK",
/* 201 */ "Created",
/* 202 */ "Accepted",
/* 203 */ "Non-Authoritative Information",
/* 204 */ "No Content",
/* 205 */ "Reset Content",
/* 206 */ "Partial Content",
/* 207 */ "Multi-Status"
},
new String[]
{
/* 300 */"Multiple Choices",
/* 301 */ "Moved Permanently",
/* 302 */ "Found",
/* 303 */ "See Other",
/* 304 */ "Not Modified",
/* 305 */ "Use Proxy",
/* 306 */ "",
/* 307 */ "Temporary Redirect"
},
new String[]
{
/* 400 */"Bad Request",
/* 401 */ "Unauthorized",
/* 402 */ "Payment Required",
/* 403 */ "Forbidden",
/* 404 */ "Not Found",
/* 405 */ "Method Not Allowed",
/* 406 */ "Not Acceptable",
/* 407 */ "Proxy Authentication Required",
/* 408 */ "Request Timeout",
/* 409 */ "Conflict",
/* 410 */ "Gone",
/* 411 */ "Length Required",
/* 412 */ "Precondition Failed",
/* 413 */ "Request Entity Too Large",
/* 414 */ "Request-Uri Too Long",
/* 415 */ "Unsupported Media Type",
/* 416 */ "Requested Range Not Satisfiable",
/* 417 */ "Expectation Failed",
/* 418 */ "",
/* 419 */ "",
/* 420 */ "",
/* 421 */ "",
/* 422 */ "Unprocessable Entity",
/* 423 */ "Locked",
/* 424 */ "Failed Dependency"
},
new String[]
{
/* 500 */"Internal Server Error",
/* 501 */ "Not Implemented",
/* 502 */ "Bad Gateway",
/* 503 */ "Service Unavailable",
/* 504 */ "Gateway Timeout",
/* 505 */ "Http Version Not Supported",
/* 506 */ "",
/* 507 */ "Insufficient Storage"
}
};
// ************************************************************************
//
// Header index to string conversions
//
//|
///
/// [To be supplied.]
///
public static int GetKnownRequestHeaderIndex(String header) {
Object intObj = s_requestHeadersLookupTable[header];
if (intObj != null)
return(Int32)intObj;
else
return -1;
}
// ************************************************************************
//|
///
/// [To be supplied.]
///
public static String GetKnownRequestHeaderName(int index) {
return s_requestHeaderNames[index];
}
// ************************************************************************
//|
///
/// [To be supplied.]
///
public static int GetKnownResponseHeaderIndex(String header) {
Object intObj = s_responseHeadersLookupTable[header];
if (intObj != null)
return(Int32)intObj;
else
return -1;
}
// ************************************************************************
//|
///
/// [To be supplied.]
///
public static String GetKnownResponseHeaderName(int index) {
return s_responseHeaderNames[index];
}
// ************************************************************************
//
// Implementation -- lookup tables for header names
//
static private String[] s_requestHeaderNames = new String[RequestHeaderMaximum];
static private String[] s_responseHeaderNames = new String[ResponseHeaderMaximum];
static private Hashtable s_requestHeadersLookupTable = new Hashtable(SymbolHashCodeProvider.Default, SymbolEqualComparer.Default);
static private Hashtable s_responseHeadersLookupTable = new Hashtable(SymbolHashCodeProvider.Default, SymbolEqualComparer.Default);
// ************************************************************************
static private void DefineHeader(bool isRequest,
bool isResponse,
int index,
String name) {
Int32 i32 = new Int32();
if (isRequest) {
i32 = index;
s_requestHeaderNames[index] = name;
s_requestHeadersLookupTable.Add(name, i32);
}
if (isResponse) {
i32 = index;
s_responseHeaderNames[index] = name;
s_responseHeadersLookupTable.Add(name, i32);
}
}
// ************************************************************************
static HttpWorkerRequest() {
//
// common headers
//
DefineHeader(true, true, HeaderCacheControl, "Cache-Control");
DefineHeader(true, true, HeaderConnection, "Connection");
DefineHeader(true, true, HeaderDate, "Date");
DefineHeader(true, true, HeaderKeepAlive, "Keep-Alive");
DefineHeader(true, true, HeaderPragma, "Pragma");
DefineHeader(true, true, HeaderTrailer, "Trailer");
DefineHeader(true, true, HeaderTransferEncoding, "Transfer-Encoding");
DefineHeader(true, true, HeaderUpgrade, "Upgrade");
DefineHeader(true, true, HeaderVia, "Via");
DefineHeader(true, true, HeaderWarning, "Warning");
DefineHeader(true, true, HeaderAllow, "Allow");
DefineHeader(true, true, HeaderContentLength, "Content-Length");
DefineHeader(true, true, HeaderContentType, "Content-Type");
DefineHeader(true, true, HeaderContentEncoding, "Content-Encoding");
DefineHeader(true, true, HeaderContentLanguage, "Content-Language");
DefineHeader(true, true, HeaderContentLocation, "Content-Location");
DefineHeader(true, true, HeaderContentMd5, "Content-MD5");
DefineHeader(true, true, HeaderContentRange, "Content-Range");
DefineHeader(true, true, HeaderExpires, "Expires");
DefineHeader(true, true, HeaderLastModified, "Last-Modified");
//
// request only headers
//
DefineHeader(true, false, HeaderAccept, "Accept");
DefineHeader(true, false, HeaderAcceptCharset, "Accept-Charset");
DefineHeader(true, false, HeaderAcceptEncoding, "Accept-Encoding");
DefineHeader(true, false, HeaderAcceptLanguage, "Accept-Language");
DefineHeader(true, false, HeaderAuthorization, "Authorization");
DefineHeader(true, false, HeaderCookie, "Cookie");
DefineHeader(true, false, HeaderExpect, "Expect");
DefineHeader(true, false, HeaderFrom, "From");
DefineHeader(true, false, HeaderHost, "Host");
DefineHeader(true, false, HeaderIfMatch, "If-Match");
DefineHeader(true, false, HeaderIfModifiedSince, "If-Modified-Since");
DefineHeader(true, false, HeaderIfNoneMatch, "If-None-Match");
DefineHeader(true, false, HeaderIfRange, "If-Range");
DefineHeader(true, false, HeaderIfUnmodifiedSince, "If-Unmodified-Since");
DefineHeader(true, false, HeaderMaxForwards, "Max-Forwards");
DefineHeader(true, false, HeaderProxyAuthorization, "Proxy-Authorization");
DefineHeader(true, false, HeaderReferer, "Referer");
DefineHeader(true, false, HeaderRange, "Range");
DefineHeader(true, false, HeaderTe, "TE");
DefineHeader(true, false, HeaderUserAgent, "User-Agent");
//
// response only headers
//
DefineHeader(false, true, HeaderAcceptRanges, "Accept-Ranges");
DefineHeader(false, true, HeaderAge, "Age");
DefineHeader(false, true, HeaderEtag, "ETag");
DefineHeader(false, true, HeaderLocation, "Location");
DefineHeader(false, true, HeaderProxyAuthenticate, "Proxy-Authenticate");
DefineHeader(false, true, HeaderRetryAfter, "Retry-After");
DefineHeader(false, true, HeaderServer, "Server");
DefineHeader(false, true, HeaderSetCookie, "Set-Cookie");
DefineHeader(false, true, HeaderVary, "Vary");
DefineHeader(false, true, HeaderWwwAuthenticate, "WWW-Authenticate");
}
}
}