//////////////////////////////////////////////////////////////////////////////// // // 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"); } } }