using System.Security;
using System.Security.Permissions;
using System.Security.Principal;
+using System.Threading;
using System.Web.Configuration;
using System.Web.Management;
using System.Web.UI;
using System.Web.Util;
using System.Globalization;
-#if NET_4_0
using System.Security.Authentication.ExtendedProtection;
using System.Web.Routing;
-#endif
namespace System.Web
{
string unescaped_path;
string original_path;
string path_info;
+ string path_info_unvalidated;
string raw_url;
+ string raw_url_unvalidated;
WebROCollection all_params;
- WebROCollection headers;
+ NameValueCollection headers;
+ WebROCollection headers_unvalidated;
Stream input_stream;
InputFilterStream input_filter;
Stream filter;
HttpCookieCollection cookies;
+ HttpCookieCollection cookies_unvalidated;
string http_method;
WebROCollection form;
bool checked_cookies, checked_query_string, checked_form;
static readonly UrlMappingCollection urlMappings;
readonly static char [] queryTrimChars = {'?'};
-#if NET_4_0
bool lazyFormValidation;
bool lazyQueryStringValidation;
bool inputValidationEnabled;
RequestContext requestContext;
+ BufferlessInputStream bufferlessInputStream;
static bool validateRequestNewMode;
internal static bool ValidateRequestNewMode {
return chars;
}
-#endif
static HttpRequest ()
{
urlMappings = null;
}
-#if NET_4_0
Version validationMode = HttpRuntime.Section.RequestValidationMode;
if (validationMode >= new Version (4, 0)) {
if (!String.IsNullOrEmpty (invalidChars))
RequestPathInvalidCharacters = CharsFromList (invalidChars);
}
-#endif
} catch {
// unlikely to happen
}
}
}
-#if !TARGET_JVM
public WindowsIdentity LogonUserIdentity {
get { throw new NotImplementedException (); }
}
-#endif
string anonymous_id;
public string AnonymousID {
public HttpBrowserCapabilities Browser {
get {
if (browser_capabilities == null)
- browser_capabilities = (HttpBrowserCapabilities)
- HttpCapabilitiesBase.GetConfigCapabilities (null, this);
+ browser_capabilities = HttpCapabilitiesBase.BrowserCapabilitiesProvider.GetBrowserCapabilities (this);
return browser_capabilities;
}
}
}
- public HttpCookieCollection Cookies {
+ internal HttpCookieCollection CookiesNoValidation {
get {
- if (cookies == null) {
+ if (cookies_unvalidated == null) {
if (worker_request == null) {
- cookies = new HttpCookieCollection ();
+ cookies_unvalidated = new HttpCookieCollection ();
} else {
string cookie_hv = worker_request.GetKnownRequestHeader (HttpWorkerRequest.HeaderCookie);
- cookies = new HttpCookieCollection (cookie_hv);
+ cookies_unvalidated = new HttpCookieCollection (cookie_hv);
}
}
-#if TARGET_J2EE
- // For J2EE portal support we emulate cookies using the session.
- GetSessionCookiesForPortal (cookies);
-#endif
+ return cookies_unvalidated;
+ }
+ }
+
+ public HttpCookieCollection Cookies {
+ get {
+ if (cookies == null) {
+ cookies = CookiesNoValidation;
+ }
+
bool needValidation = validate_cookies;
-#if NET_4_0
needValidation |= validateRequestNewMode;
-#endif
if (needValidation && !checked_cookies) {
// Setting this before calling the validator prevents
// possible endless recursion
return FilePath;
}
}
-#if NET_4_0
public string CurrentExecutionFilePathExtension {
get { return global::System.IO.Path.GetExtension (CurrentExecutionFilePath); }
}
-#endif
public string AppRelativeCurrentExecutionFilePath {
get {
return VirtualPathUtility.ToAppRelative (CurrentExecutionFilePath);
// GetSubStream returns a 'copy' of the InputStream with Position set to 0.
static Stream GetSubStream (Stream stream)
{
-#if !TARGET_JVM
if (stream is IntPtrStream)
return new IntPtrStream (stream);
-#endif
if (stream is MemoryStream) {
MemoryStream other = (MemoryStream) stream;
//
// Loads the form data from on a application/x-www-form-urlencoded post
//
-#if TARGET_J2EE
- void RawLoadWwwForm ()
-#else
void LoadWwwForm ()
-#endif
{
using (Stream input = GetSubStream (InputStream)) {
using (StreamReader s = new StreamReader (input, ContentEncoding)) {
public NameValueCollection Form {
get {
NameValueCollection form = FormUnvalidated;
-#if NET_4_0
if (validateRequestNewMode && !checked_form) {
if (!lazyFormValidation) {
// Setting this before calling the validator prevents
ValidateNameValueCollection ("Form", form, RequestValidationSource.Form);
}
} else
-#endif
if (validate_form && !checked_form){
checked_form = true;
ValidateNameValueCollection ("Form", form);
}
}
+ internal NameValueCollection HeadersNoValidation {
+ get {
+ if (headers_unvalidated == null) {
+ headers_unvalidated = new HeadersCollection (this);
+ }
+
+ return headers_unvalidated;
+ }
+ }
+
public NameValueCollection Headers {
get {
if (headers == null) {
- headers = new HeadersCollection (this);
-#if NET_4_0
+ headers = HeadersNoValidation;
if (validateRequestNewMode) {
RequestValidator validator = RequestValidator.Current;
int validationFailureIndex;
ThrowValidationException ("Headers", hkey, value);
}
}
-#endif
}
return headers;
input_stream = new MemoryStream (ms.GetBuffer (), 0, (int) ms.Length, false, true);
}
-#if !TARGET_JVM
const int INPUT_BUFFER_SIZE = 32*1024;
TempFileStream GetTempStream ()
if (total < content_length)
throw HttpException.NewWithCode (411, "The request body is incomplete.", WebEventCodes.WebErrorOtherError);
}
-#endif
internal void ReleaseResources ()
{
} catch {}
}
}
-#if NET_4_0
public RequestContext RequestContext {
get {
if (requestContext == null)
throw new PlatformNotSupportedException ("This property is not supported.");
}
}
-#endif
+
+ public Stream GetBufferedInputStream ()
+ {
+ return input_stream;
+ }
+
+ public Stream GetBufferlessInputStream ()
+ {
+ if (bufferlessInputStream == null) {
+ if (input_stream != null)
+ throw new HttpException ("Input stream has already been created");
+
+ // we don't need to hook up the filter here, because the raw stream should be returned
+ bufferlessInputStream = new BufferlessInputStream (this);
+ }
+
+ return bufferlessInputStream;
+ }
+
+ public Stream GetBufferlessInputStream (bool disableMaxRequestLength)
+ {
+ return GetBufferlessInputStream ();
+ }
+
+ //
+ // Stream that returns the data as it is read, without buffering
+ //
+ class BufferlessInputStream : Stream {
+ HttpRequest request;
+
+ // cached, the request content-length
+ int content_length;
+
+ // buffer that holds preloaded data
+ byte [] preloadedBuffer;
+
+ // indicates if we already served the whole preloaded buffer
+ bool preloaded_served;
+
+ // indicates if we already checked the request content-length against httpRuntime limit
+ bool checked_maxRequestLength;
+
+ // our stream position
+ long position;
+
+ //
+ // @request: the containing request that created us, used to find out content length
+ public BufferlessInputStream (HttpRequest request)
+ {
+ this.request = request;
+ content_length = request.ContentLength;
+ }
+
+ public override bool CanRead {
+ get { return true; }
+ }
+
+ public override bool CanSeek {
+ get { return false; }
+ }
+
+ public override bool CanWrite {
+ get { return false; }
+ }
+
+ public override long Length {
+ get {
+ return content_length;
+ }
+ }
+
+ public override long Position {
+ get {
+ return position;
+ }
+ set {
+ throw new NotSupportedException ("This is a readonly stream");
+ }
+ }
+
+ public override void Flush ()
+ {
+ }
+
+ public override int Read (byte [] buffer, int offset, int count)
+ {
+ if (buffer == null)
+ throw new ArgumentNullException ("buffer");
+
+ if (offset < 0 || count < 0)
+ throw new ArgumentOutOfRangeException ("offset or count less than zero.");
+
+ if (buffer.Length - offset < count )
+ throw new ArgumentException ("offset+count",
+ "The size of the buffer is less than offset + count.");
+
+ if (count == 0 || request.worker_request == null)
+ return 0;
+
+ if (!checked_maxRequestLength) {
+ int content_length_kb = content_length / 1024;
+ HttpRuntimeSection config = HttpRuntime.Section;
+ if (content_length_kb > config.MaxRequestLength)
+ throw HttpException.NewWithCode (400, "Upload size exceeds httpRuntime limit.", WebEventCodes.RuntimeErrorPostTooLarge);
+ else
+ checked_maxRequestLength = true;
+ }
+
+ // Serve the bytes we might have preloaded already.
+ if (!preloaded_served) {
+ if (preloadedBuffer == null)
+ preloadedBuffer = request.worker_request.GetPreloadedEntityBody ();
+
+ if (preloadedBuffer != null) {
+ long bytes_left = preloadedBuffer.Length-position;
+ int n = (int) Math.Min (count, bytes_left);
+ Array.Copy (preloadedBuffer, position, buffer, offset, n);
+ position += n;
+
+ if (n == bytes_left)
+ preloaded_served = true;
+
+ return n;
+ }
+ else
+ preloaded_served = true;
+ }
+
+ // serve bytes from worker request if available
+ if (position < content_length) {
+ long bytes_left = content_length-position;
+ int n = count;
+
+ if (bytes_left < count)
+ n = (int) bytes_left;
+
+ int bytes_read = request.worker_request.ReadEntityBody (buffer, offset, n);
+ position += bytes_read;
+ return bytes_read;
+ }
+
+ return 0;
+ }
+
+ public override long Seek (long offset, SeekOrigin origin)
+ {
+ throw new NotSupportedException ("Can not seek on the HttpRequest.BufferlessInputStream");
+ }
+
+ public override void SetLength (long value)
+ {
+ throw new NotSupportedException ("Can not set length on the HttpRequest.BufferlessInputStream");
+ }
+
+ public override void Write (byte [] buffer, int offset, int count)
+ {
+ throw new NotSupportedException ("Can not write on the HttpRequest.BufferlessInputStream");
+ }
+
+ //
+ // TODO: explicitly support the async methods if there is a convenient way of doing it
+ //
+ }
public Stream InputStream {
get {
if (input_stream == null)
get {
if (unescaped_path == null) {
unescaped_path = PathNoValidation;
-#if NET_4_0
if (validateRequestNewMode) {
RequestValidator validator = RequestValidator.Current;
int validationFailureIndex;
if (!validator.IsValidRequestString (HttpContext.Current, unescaped_path, RequestValidationSource.Path, null, out validationFailureIndex))
ThrowValidationException ("Path", "Path", unescaped_path);
}
-#endif
}
return unescaped_path;
}
}
+ internal string PathInfoNoValidation {
+ get {
+ if (path_info_unvalidated == null) {
+ if (worker_request == null)
+ return String.Empty;
+
+ path_info_unvalidated = worker_request.GetPathInfo () ?? String.Empty;
+ }
+
+ return path_info_unvalidated;
+ }
+ }
+
public string PathInfo {
get {
if (path_info == null) {
- if (worker_request == null)
- return String.Empty;
- path_info = worker_request.GetPathInfo () ?? String.Empty;
-#if NET_4_0
+ path_info = PathInfoNoValidation;
if (validateRequestNewMode) {
RequestValidator validator = RequestValidator.Current;
int validationFailureIndex;
if (!validator.IsValidRequestString (HttpContext.Current, path_info, RequestValidationSource.PathInfo, null, out validationFailureIndex))
ThrowValidationException ("PathInfo", "PathInfo", path_info);
}
-#endif
}
return path_info;
public NameValueCollection QueryString {
get {
NameValueCollection query_string_nvc = QueryStringUnvalidated;
-#if NET_4_0
if (validateRequestNewMode && !checked_query_string) {
if (!lazyQueryStringValidation) {
// Setting this before calling the validator prevents
ValidateNameValueCollection ("QueryString", query_string_nvc, RequestValidationSource.QueryString);
}
} else
-#endif
if (validate_query_string && !checked_query_string) {
// Setting this before calling the validator prevents
// possible endless recursion
}
}
- public string RawUrl {
+ internal string RawUrlUnvalidated {
get {
- if (raw_url == null) {
+ if (raw_url_unvalidated == null) {
if (worker_request != null)
- raw_url = worker_request.GetRawUrl ();
+ raw_url_unvalidated = worker_request.GetRawUrl ();
else
- raw_url = UrlComponents.Path + UrlComponents.Query;
+ raw_url_unvalidated = UrlComponents.Path + UrlComponents.Query;
- if (raw_url == null)
- raw_url = String.Empty;
-#if NET_4_0
+ if (raw_url_unvalidated == null)
+ raw_url_unvalidated = String.Empty;
+ }
+
+ return raw_url_unvalidated;
+ }
+ }
+
+ public string RawUrl {
+ get {
+ if (raw_url == null) {
+ raw_url = RawUrlUnvalidated;
if (validateRequestNewMode) {
RequestValidator validator = RequestValidator.Current;
int validationFailureIndex;
if (!validator.IsValidRequestString (HttpContext.Current, raw_url, RequestValidationSource.RawUrl, null, out validationFailureIndex))
ThrowValidationException ("RawUrl", "RawUrl", raw_url);
}
-#endif
}
return raw_url;
}
}
+ public CancellationToken TimedOutToken {
+ get {
+ throw new NotImplementedException ();
+ }
+ }
+
public int TotalBytes {
get {
Stream ins = InputStream;
}
}
+ public UnvalidatedRequestValues Unvalidated {
+ get {
+ var vals = new UnvalidatedRequestValues ();
+
+ vals.Cookies = CookiesNoValidation;
+ vals.Files = Files;
+ vals.Form = FormUnvalidated;
+ vals.Headers = HeadersNoValidation;
+ vals.Path = PathNoValidation;
+ vals.PathInfo = PathInfoNoValidation;
+ vals.QueryString = QueryStringUnvalidated;
+ vals.RawUrl = RawUrlUnvalidated;
+ vals.Url = Url;
+
+ return vals;
+ }
+ }
+
public Uri Url {
get {
if (cached_url == null) {
}
public int [] MapImageCoordinates (string imageFieldName)
+ {
+ string[] parameters = GetImageCoordinatesParameters (imageFieldName);
+ if (parameters == null)
+ return null;
+ int [] result = new int [2];
+ try {
+ result [0] = Int32.Parse (parameters [0]);
+ result [1] = Int32.Parse (parameters [1]);
+ } catch {
+ return null;
+ }
+
+ return result;
+ }
+
+ public double [] MapRawImageCoordinates (string imageFieldName)
+ {
+ string[] parameters = GetImageCoordinatesParameters (imageFieldName);
+ if (parameters == null)
+ return null;
+ double [] result = new double [2];
+ try {
+ result [0] = Double.Parse (parameters [0]);
+ result [1] = Double.Parse (parameters [1]);
+ } catch {
+ return null;
+ }
+
+ return result;
+ }
+
+ string [] GetImageCoordinatesParameters (string imageFieldName)
{
string method = HttpMethod;
NameValueCollection coll = null;
string y = coll [imageFieldName + ".y"];
if (y == null || y == "")
return null;
-
- int [] result = new int [2];
- try {
- result [0] = Int32.Parse (x);
- result [1] = Int32.Parse (y);
- } catch {
- return null;
- }
+ string[] result = new string [] { x, y };
return result;
}
if (!isAppVirtualPath && !virtualPath.StartsWith (appVirtualPath, RuntimeHelpers.StringComparison))
throw new InvalidOperationException (String.Format ("Failed to map path '{0}'", virtualPath));
-#if TARGET_JVM
- return worker_request.MapPath (virtualPath);
-#else
string path = worker_request.MapPath (virtualPath);
if (virtualPath [virtualPath.Length - 1] != '/' && path [path.Length - 1] == System.IO.Path.DirectorySeparatorChar)
path = path.TrimEnd (System.IO.Path.DirectorySeparatorChar);
return path;
-#endif
}
public void SaveAs (string filename, bool includeHeaders)
validate_cookies = true;
validate_query_string = true;
validate_form = true;
-#if NET_4_0
inputValidationEnabled = true;
-#endif
}
-#if NET_4_0
internal void Validate ()
{
var cfg = HttpRuntime.Section;
if (validateRequestNewMode)
ValidateInput ();
}
-#endif
#region internal routines
internal string ClientTarget {
get {
string path = UrlComponents.Path;
UrlComponents.Path = path + PathInfo;
}
-#if NET_4_0
internal void SetFormCollection (WebROCollection coll, bool lazyValidation)
{
if (coll == null)
query_string_nvc = coll;
lazyQueryStringValidation = lazyValidation;
}
-#endif
// Headers is ReadOnly, so we need this hack for cookie-less sessions.
internal void SetHeader (string name, string value)
{
ThrowValidationException (name, key, val);
}
}
-#if NET_4_0
static void ValidateNameValueCollection (string name, NameValueCollection coll, RequestValidationSource source)
{
if (coll == null)
{
throw new PlatformNotSupportedException ("This method is not supported.");
}
-#endif
static void ValidateCookieCollection (HttpCookieCollection cookies)
{
if (cookies == null)
int size = cookies.Count;
HttpCookie cookie;
-#if NET_4_0
RequestValidator validator = RequestValidator.Current;
int validationFailureIndex;
HttpContext context = HttpContext.Current;
-#endif
bool invalid;
for (int i = 0 ; i < size ; i++) {
string name = cookie.Name;
if (!String.IsNullOrEmpty (value)) {
-#if NET_4_0
if (validateRequestNewMode)
invalid = !validator.IsValidRequestString (context, value, RequestValidationSource.Cookies, name, out validationFailureIndex);
else
-#endif
invalid = IsInvalidString (value);
if (invalid)
throw new HttpRequestValidationException (msg);
}
-#if NET_4_0
internal static void ValidateString (string key, string value, RequestValidationSource source)
{
if (String.IsNullOrEmpty (value))
if (IsInvalidString (value, out ignore))
ThrowValidationException (source.ToString (), key, value);
}
-#endif
internal static bool IsInvalidString (string val)
{
#pragma warning disable 219
#endregion
#region Helper classes
-
+
//
// Stream-based multipart handling.
//