// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
-#if NET_2_0 && SECURITY_DEP
+#if SECURITY_DEP
using System.Globalization;
using System.IO;
string status_description = "OK";
bool chunked;
HttpListenerContext context;
+
internal bool HeadersSent;
+ internal object headers_lock = new object ();
+
bool force_close_chunked;
internal HttpListenerResponse (HttpListenerContext context)
void Close (bool force)
{
- // TODO: use the 'force' argument
- context.Connection.Close ();
disposed = true;
+ context.Connection.Close (force);
}
public void Close ()
internal void SendHeaders (bool closing, MemoryStream ms)
{
- //TODO: When do we send KeepAlive?
Encoding encoding = content_encoding;
if (encoding == null)
encoding = Encoding.Default;
if (content_type != null) {
- if (content_encoding != null && content_type.IndexOf ("charset=") == -1) {
+ if (content_encoding != null && content_type.IndexOf ("charset=", StringComparison.Ordinal) == -1) {
string enc_name = content_encoding.WebName;
headers.SetInternal ("Content-Type", content_type + "; charset=" + enc_name);
} else {
status_code == 503);
if (conn_close == false)
- conn_close = (context.Request.Headers ["connection"] == "close");
+ conn_close = !context.Request.KeepAlive;
// They sent both KeepAlive: true and Connection: close!?
- if (!keep_alive || conn_close)
+ if (!keep_alive || conn_close) {
headers.SetInternal ("Connection", "close");
+ conn_close = true;
+ }
if (chunked)
headers.SetInternal ("Transfer-Encoding", "chunked");
- int chunked_uses = context.Connection.ChunkedUses;
- if (chunked_uses >= 100) {
+ int reuses = context.Connection.Reuses;
+ if (reuses >= 100) {
force_close_chunked = true;
- if (!conn_close)
+ if (!conn_close) {
headers.SetInternal ("Connection", "close");
+ conn_close = true;
+ }
+ }
+
+ if (!conn_close) {
+ headers.SetInternal ("Keep-Alive", String.Format ("timeout=15,max={0}", 100 - reuses));
+ if (context.Request.ProtocolVersion <= HttpVersion.Version10)
+ headers.SetInternal ("Connection", "keep-alive");
}
if (location != null)
headers.SetInternal ("Location", location);
if (cookies != null) {
- bool firstDone = false;
- StringBuilder cookieSB = new StringBuilder ();
- foreach (Cookie cookie in cookies) {
- if (firstDone)
- cookieSB.Append (",");
- firstDone = true;
- cookieSB.Append (cookie.ToClientString ());
- }
- headers.SetInternal("Set-Cookie2", cookieSB.ToString ());
+ foreach (Cookie cookie in cookies)
+ headers.SetInternal ("Set-Cookie", CookieToClientString (cookie));
}
- StreamWriter writer = new StreamWriter (ms, encoding);
+ StreamWriter writer = new StreamWriter (ms, encoding, 256);
writer.Write ("HTTP/{0} {1} {2}\r\n", version, status_code, status_description);
- string headers_str = headers.ToString ();
+ string headers_str = headers.ToStringMultiValue ();
writer.Write (headers_str);
writer.Flush ();
- int preamble = encoding.GetPreamble ().Length;
+ int preamble = (encoding.CodePage == 65001) ? 3 : encoding.GetPreamble ().Length;
if (output_stream == null)
output_stream = context.Connection.GetResponseStream ();
HeadersSent = true;
}
+ static string CookieToClientString (Cookie cookie)
+ {
+ if (cookie.Name.Length == 0)
+ return String.Empty;
+
+ StringBuilder result = new StringBuilder (64);
+
+ if (cookie.Version > 0)
+ result.Append ("Version=").Append (cookie.Version).Append (";");
+
+ result.Append (cookie.Name).Append ("=").Append (cookie.Value);
+
+ if (cookie.Path != null && cookie.Path.Length != 0)
+ result.Append (";Path=").Append (QuotedString (cookie, cookie.Path));
+
+ if (cookie.Domain != null && cookie.Domain.Length != 0)
+ result.Append (";Domain=").Append (QuotedString (cookie, cookie.Domain));
+
+ if (cookie.Port != null && cookie.Port.Length != 0)
+ result.Append (";Port=").Append (cookie.Port);
+
+ return result.ToString ();
+ }
+
+ static string QuotedString (Cookie cookie, string value)
+ {
+ if (cookie.Version == 0 || IsToken (value))
+ return value;
+ else
+ return "\"" + value.Replace("\"", "\\\"") + "\"";
+ }
+
+ static string tspecials = "()<>@,;:\\\"/[]?={} \t"; // from RFC 2965, 2068
+
+ static bool IsToken (string value)
+ {
+ int len = value.Length;
+ for (int i = 0; i < len; i++) {
+ char c = value [i];
+ if (c < 0x20 || c >= 0x7f || tspecials.IndexOf (c) != -1)
+ return false;
+ }
+ return true;
+ }
+
public void SetCookie (Cookie cookie)
{
if (cookie == null)