// Gonzalo Paniagua Javier (gonzalo@ximian.com)
// Marek Habersack <mhabersack@novell.com>
//
-// Copyright (C) 2005-2009 Novell, Inc (http://www.novell.com)
+// Copyright (C) 2005-2010 Novell, Inc (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// the headers that we compute here.
//
- NameValueCollection headers;
+ HttpHeaderCollection headers;
bool headers_sent;
NameValueCollection cached_headers;
internal bool use_chunked;
bool closed;
+ bool completed;
internal bool suppress_content;
//
this.context = context;
#if !TARGET_J2EE
- if (worker_request != null)
- use_chunked = (worker_request.GetHttpVersion () == "HTTP/1.1");
+ if (worker_request != null && worker_request.GetHttpVersion () == "HTTP/1.1") {
+ string gi = worker_request.GetServerVariable ("GATEWAY_INTERFACE");
+ use_chunked = (String.IsNullOrEmpty (gi) ||
+ !gi.StartsWith ("cgi", StringComparison.OrdinalIgnoreCase));
+ } else {
+ use_chunked = false;
+ }
#endif
writer = new HttpWriter (this);
}
get {
if (!version_header_checked && version_header == null) {
version_header_checked = true;
- HttpRuntimeSection config = WebConfigurationManager.GetWebApplicationSection ("system.web/httpRuntime") as HttpRuntimeSection;
+ HttpRuntimeSection config = HttpRuntime.Section;
if (config != null && config.EnableVersionHeader)
version_header = Environment.Version.ToString (3);
}
return version_header;
}
}
-
+
+ internal HttpContext Context {
+ get { return context; }
+ set { context = value; }
+ }
+
internal string[] FileDependencies {
get {
if (fileDependencies == null || fileDependencies.Count == 0)
public NameValueCollection Headers {
get {
if (headers == null)
- headers = new NameValueCollection ();
+ headers = new HttpHeaderCollection ();
return headers;
}
public void AppendHeader (string name, string value)
{
if (headers_sent)
- throw new HttpException ("headers have been already sent");
-
+ throw new HttpException ("Headers have been already sent");
#if !TARGET_J2EE
- if (String.Compare (name, "content-length", true, Helpers.InvariantCulture) == 0){
+ if (String.Compare (name, "content-length", StringComparison.OrdinalIgnoreCase) == 0){
content_length = (long) UInt64.Parse (value);
use_chunked = false;
return;
}
#endif
- if (String.Compare (name, "content-type", true, Helpers.InvariantCulture) == 0){
+ if (String.Compare (name, "content-type", StringComparison.OrdinalIgnoreCase) == 0){
ContentType = value;
return;
}
#if !TARGET_J2EE
- if (String.Compare (name, "transfer-encoding", true, Helpers.InvariantCulture) == 0){
+ if (String.Compare (name, "transfer-encoding", StringComparison.OrdinalIgnoreCase) == 0){
transfer_encoding = value;
use_chunked = false;
return;
}
#endif
- if (String.Compare (name, "cache-control", true, Helpers.InvariantCulture) == 0){
+ if (String.Compare (name, "cache-control", StringComparison.OrdinalIgnoreCase) == 0){
user_cache_control = value;
return;
}
public string ApplyAppPathModifier (string virtualPath)
{
- if (virtualPath == null)
+ if (virtualPath == null || context == null)
return null;
if (virtualPath.Length == 0)
internal void Flush (bool final_flush)
{
+ if (completed)
+ throw new HttpException ("Server cannot flush a completed response");
+
DoFilter (final_flush);
if (!headers_sent){
if (final_flush || status_code != 200)
output_stream.Clear ();
if (WorkerRequest != null)
output_stream.Flush (WorkerRequest, true); // ignore final_flush here.
+ completed = true;
return;
}
-
+ completed = final_flush;
+
if (!headers_sent)
WriteHeaders (final_flush);
isFullyQualified = false;
if (!isFullyQualified) {
- HttpRuntimeSection config = WebConfigurationManager.GetWebApplicationSection ("system.web/httpRuntime") as HttpRuntimeSection;
+ HttpRuntimeSection config = HttpRuntime.Section;
if (config != null && config.UseFullyQualifiedRedirectUrl) {
var ub = new UriBuilder (context.Request.Url);
- ub.Path = url;
+ int qpos = url.IndexOf ('?');
+ if (qpos == -1) {
+ ub.Path = url;
+ ub.Query = null;
+ } else {
+ ub.Path = url.Substring (0, qpos);
+ ub.Query = url.Substring (qpos + 1);
+ }
ub.Fragment = null;
ub.Password = null;
- ub.Query = null;
ub.UserName = null;
url = ub.Uri.ToString ();
}
writer.Write (buffer, index, count);
}
+ bool IsFileSystemDirSeparator (char ch)
+ {
+ return ch == '\\' || ch == '/';
+ }
+
+ string GetNormalizedFileName (string fn)
+ {
+ if (String.IsNullOrEmpty (fn))
+ return fn;
+
+ // On Linux we don't change \ to / since filenames with \ are valid. We also
+ // don't remove drive: designator for the same reason.
+ int len = fn.Length;
+ if (len >= 3 && fn [1] == ':' && IsFileSystemDirSeparator (fn [2]))
+ return Path.GetFullPath (fn); // drive-qualified absolute file path
+
+ bool startsWithDirSeparator = IsFileSystemDirSeparator (fn [0]);
+ if (len >= 2 && startsWithDirSeparator && IsFileSystemDirSeparator (fn [1]))
+ return Path.GetFullPath (fn); // UNC path
+
+ if (!startsWithDirSeparator) {
+ HttpContext ctx = context ?? HttpContext.Current;
+ HttpRequest req = ctx != null ? ctx.Request : null;
+
+ if (req != null)
+ return req.MapPath (fn);
+ }
+
+ return fn; // Or should we rather throw?
+ }
+
internal void WriteFile (FileStream fs, long offset, long size)
{
byte [] buffer = new byte [32*1024];
if (filename == null)
throw new ArgumentNullException ("filename");
+ string fn = GetNormalizedFileName (filename);
if (readIntoMemory){
- using (FileStream fs = File.OpenRead (filename))
+ using (FileStream fs = File.OpenRead (fn))
WriteFile (fs, 0, fs.Length);
} else {
- FileInfo fi = new FileInfo (filename);
- output_stream.WriteFile (filename, 0, fi.Length);
+ FileInfo fi = new FileInfo (fn);
+ output_stream.WriteFile (fn, 0, fi.Length);
}
if (buffer)
return;
internal void ReleaseResources ()
{
- output_stream.ReleaseResources (true);
- output_stream = null;
+ if (output_stream != null)
+ output_stream.ReleaseResources (true);
+ if (completed)
+ return;
+
+ Close ();
+ completed = true;
}
}