private static void HtmlAttributeEncodeInternal(string value, HttpWriter writer) { int pos = IndexOfHtmlAttributeEncodingChars(value, 0); if (pos == -1) { writer.Write(value); return; } int cch = value.Length; int startPos = 0; for (; ;) { if (pos > startPos) { writer.WriteString(value, startPos, pos - startPos); } char ch = value[pos]; switch (ch) { case '"': writer.Write("""); break; case '\'': writer.Write("'"); break; case '&': writer.Write("&"); break; case '<': // Whidbey 32404: The character '<' is not valid in an XML attribute value. // (See the W3C XML rec). writer.Write("<"); break; } startPos = pos + 1; if (startPos >= cch) { break; } pos = IndexOfHtmlAttributeEncodingChars(value, startPos); if (pos == -1) { writer.WriteString(value, startPos, cch - startPos); break; } } }
public void NullWrites() { object null_object = null; string null_string = null; writer.Write(null_string); writer.Write(null_object); writer.WriteString(null, 0, 0); }
private static void HtmlAttributeEncodeInternal(string value, HttpWriter writer) { int num = IndexOfHtmlAttributeEncodingChars(value, 0); if (num == -1) { writer.Write(value); return; } int length = value.Length; int index = 0; Label_001D: if (num > index) { writer.WriteString(value, index, num - index); } switch (value[num]) { case '&': writer.Write("&"); break; case '\'': writer.Write("'"); break; case '<': writer.Write("<"); break; case '"': writer.Write("""); break; } index = num + 1; if (index < length) { num = IndexOfHtmlAttributeEncodingChars(value, index); if (num != -1) { goto Label_001D; } writer.WriteString(value, index, length - index); } }
public void Methods_Deny_Unrestricted() { writer.Write(Char.MinValue); writer.Write(this); writer.Write(String.Empty); writer.Write(new char [1], 0, 1); writer.WriteLine(); writer.WriteString("mono", 0, 4); writer.WriteBytes(new byte[1], 0, 1); writer.Flush(); writer.Close(); }
/// <summary> /// Private method that handles an incoming request. /// It sets up a RequestHandlerContext instance with the data from /// the incoming HTTP request, finds a suitable request handler to /// produce the response, and then sends the response as an HTTP /// response back to the client. /// Preconditions /// "connection is open" /// serviceRoot != null /// serviceRoot.Length > 8 /// "serviceRoot starts with 'http://' and ends with '/'" /// requestRouting != null /// </summary> /// <param name="connection">Open TCP/IP connection</param> /// <param name="serviceRoot">The absolute URI that is a prefix of /// all request URIs that this web service supports. It must start /// with "http://" and must end with "/".</param> /// <param name="relayDomain">Host name or Internet address of the /// relay to be used, or null if no relay is used</param> /// <param name="requestRouting">Collection of /// { request pattern, request handler} /// pairs</param> /// <param name="connectionClose">Return parameter that indicates /// that the connection should be closed after this call. This may /// be because the incoming request has a "Connection: close" /// header, because the request handler has set the /// ConnectionClose property, or because some error occurred. /// </param> internal static void ConsumeRequest(Stream connection, string serviceRoot, string relayDomain, RequestRouting requestRouting, ref bool connectionClose) { Contract.Requires(connection != null); Contract.Requires(serviceRoot != null); Contract.Requires(serviceRoot.Length > 8); Contract.Requires(serviceRoot.Substring(0, 7) == "http://"); Contract.Requires(serviceRoot[serviceRoot.Length - 1] != '/'); Contract.Requires(requestRouting != null); // initialization -------------------------------------------- HttpReader reader = new HttpReader(); HttpWriter writer = new HttpWriter(); var context = new RequestHandlerContext(serviceRoot, relayDomain); // Both client and server may request closing the connection. // Initially, we assume that neither one wants to close the // connection. context.ConnectionClose = false; // receive request ------------------------------------------- reader.Attach(connection); // request line string httpMethod; string requestUri; string httpVersion; reader.ReadStringToBlank(out httpMethod); reader.ReadStringToBlank(out requestUri); reader.ReadFieldValue(out httpVersion); if (reader.Status != HttpStatus.BeforeContent) // error { reader.Detach(); connectionClose = true; return; } context.RequestMethod = httpMethod; context.RequestUri = requestUri; // ignore version // headers string fieldName; string fieldValue; int requestContentLength = -1; reader.ReadFieldName(out fieldName); while (reader.Status == HttpStatus.BeforeContent) { reader.ReadFieldValue(out fieldValue); if (fieldValue != null) { Contract.Assert(reader.Status == HttpStatus.BeforeContent); if (fieldName == "Connection") { context.ConnectionClose = ((fieldValue == "close") || (fieldValue == "Close")); } else if (fieldName == "Content-Type") { context.RequestContentType = fieldValue; } else if (fieldName == "Content-Length") { if (Utilities.TryParseUInt32(fieldValue, out requestContentLength)) { // content length is now known } else { reader.Status = HttpStatus.SyntaxError; reader.Detach(); connectionClose = true; return; } } } else { // it's ok to skip header whose value is too long } Contract.Assert(reader.Status == HttpStatus.BeforeContent); reader.ReadFieldName(out fieldName); } if (reader.Status != HttpStatus.InContent) { reader.Detach(); connectionClose = true; return; } // content if (requestContentLength > 0) { // receive content var requestContent = new byte[requestContentLength]; int toRead = requestContentLength; var read = 0; while ((toRead > 0) && (read >= 0)) { // already read: requestContentLength - toRead read = reader.ReadContent(requestContent, requestContentLength - toRead, toRead); if (read < 0) { break; } // timeout or shutdown toRead = toRead - read; } try { char[] chars = Encoding.UTF8.GetChars(requestContent); context.RequestContent = new string(chars); } catch (Exception) { context.RequestContentType = "text/plain"; context.RequestContent = "request content is not in UTF8 format"; Debug.Print(context.RequestContent); // TODO signal wrong content format through HTTP status code 400 (Bad Request)? } } reader.Detach(); if (reader.Status != HttpStatus.InContent) { connectionClose = true; return; } // delegate request processing to a request handler ---------- var match = false; foreach (Element e in requestRouting) { if (context.RequestMatch(e)) { bool connClose = context.ConnectionClose; context.ResponseStatusCode = -1; // undefined Contract.Requires(context.ResponseContentType != null); Contract.Requires(context.ResponseContentType == "text/plain"); // default try { e.Handler(context); } catch (Exception h) { Debug.Print("exception in request handler: " + h); // TODO how to better handle handler exceptions? throw; // rethrow, to avoid masking of errors } Contract.Ensures(context.ResponseStatusCode >= 100); Contract.Ensures(context.ResponseStatusCode < 600); Contract.Ensures(context.ResponseContentType != null); Contract.Ensures(context.ResponseContentType.Length > 0); // make sure that handler has not reset connectionClose flag: Contract.Ensures((!connClose) || (context.ConnectionClose)); match = true; break; } } if (!match) { context.ResponseStatusCode = 404; // Not Found context.ResponseContentType = "text/plain"; context.ResponseContent = null; } uint availableMemory = Debug.GC(true); Debug.Print(context.RequestMethod + " " + context.RequestUri + " -> " + context.ResponseStatusCode + " [" + availableMemory + "]"); // send response --------------------------------------------- writer.Attach(connection); // status line writer.WriteString("HTTP/1.1 "); writer.WriteString(context.ResponseStatusCode.ToString()); writer.WriteLine(" "); // omit optional reason phrase // headers if (connectionClose) // TODO (context.ConnectionClose) { writer.WriteLine("Connection: close"); } byte[] responseBuffer = null; var responseLength = 0; if (context.ResponseContent != null) { responseBuffer = Encoding.UTF8.GetBytes(context.ResponseContent); responseLength = responseBuffer.Length; writer.WriteString("Content-Type: "); writer.WriteLine(context.ResponseContentType); } else { responseLength = 0; } writer.WriteString("Content-Length: "); writer.WriteLine(responseLength.ToString()); if (context.ResponseMaxAge > 0) { writer.WriteLine("Cache-Control: max-age=" + context.ResponseMaxAge); } else if (context.ResponseMaxAge == 0) { writer.WriteLine("Cache-Control: no-cache"); } // content writer.WriteBeginOfContent(); if (context.ResponseContent != null) // send content { writer.WriteContent(responseBuffer, 0, responseLength); } writer.Detach(); connectionClose = context.ConnectionClose; }