2008-12-30 30 views
7

Estoy escribiendo una aplicación de servidor web en C# y el uso de la clase StreamReader para leer de un NetworkStream subyacente:¿Cómo limitar el número de caracteres leídos por StreamReader.ReadLine() en .NET?

NetworkStream ns = new NetworkStream(clientSocket); 
StreamReader sr = new StreamReader(ns); 
String request = sr.ReadLine(); 

Este código es propenso a ataques de denegación de servicio, porque si el atacante no se desconecta nunca vamos a terminar de leer la línea. ¿Hay alguna manera de limitar el número de caracteres leídos por StreamReader.ReadLine() en .NET?

Respuesta

10

Debería utilizar la sobrecarga Read(char[], int, int) (que limita la longitud) y hacer su propia detección de fin de línea; no debería ser demasiado complicado.

Para una versión ligeramente más lento (que utiliza la versión de characted sola lectura):

static IEnumerable<string> ReadLines(string path, int maxLineLength) 
{ 
    StringBuilder currentLine = new StringBuilder(maxLineLength); 
    using (var reader = File.OpenText(path)) 
    { 
     int i; 
     while((i = reader.Read()) > 0) { 
      char c = (char) i; 
      if(c == '\r' || c == '\n') { 
       yield return currentLine.ToString(); 
       currentLine.Length = 0; 
       continue; 
      } 
      currentLine.Append((char)c); 
      if (currentLine.Length > maxLineLength) 
      { 
       throw new InvalidOperationException("Max length exceeded"); 
      } 
     } 
     if (currentLine.Length > 0) 
     { 
      yield return currentLine.ToString(); 
     }     
    } 
} 
4

Es posible que tenga uno de StreamReader.Read sobrecarga:

Tomado de http://msdn.microsoft.com/en-us/library/9kstw824.aspx

using (StreamReader sr = new StreamReader(path)) 
    { 
     //This is an arbitrary size for this example. 
     char[] c = null; 

     while (sr.Peek() >= 0) 
     { 
      c = new char[5]; 
      sr.Read(c, 0, c.Length); 
      //The output will look odd, because 
      //only five characters are read at a time. 
      Console.WriteLine(c); 
     } 
    } 

Enfoque en la línea sr.Read(c, 0, c.Length). Esto lee solo 5 caracteres de la secuencia y los ingresa en la matriz c. Es posible que desee cambiar 5 al valor que desee.

2

Aquí es mi propia solución basada en la solución de Marc Gravell:

using System; 
using System.IO; 
using System.Text; 

namespace MyProject 
{ 
    class StreamReaderExt : StreamReader 
    { 

     public StreamReaderExt(Stream s, Encoding e) : base(s, e) 
     {    
     } 

     /// <summary> 
     /// Reads a line of characters terminated by CR+LF from the current stream and returns the data as a string 
     /// </summary> 
     /// <param name="maxLineLength">Maximum allowed line length</param> 
     /// <exception cref="System.IO.IOException" /> 
     /// <exception cref="System.InvalidOperationException">When string read by this method exceeds the maximum allowed line length</exception> 
     /// <returns></returns> 
     public string ReadLineCRLF(int maxLineLength) 
     { 
      StringBuilder currentLine = new StringBuilder(maxLineLength); 

      int i; 
      bool foundCR = false; 
      bool readData = false; 

      while ((i = Read()) > 0) 
      { 

       readData = true; 

       char c = (char)i; 

       if (foundCR) 
       { 
        if (c == '\r') 
        { 
         // If CR was found before , and the next character is also CR, 
         // adding previously skipped CR to the result string 
         currentLine.Append('\r'); 
         continue; 
        } 
        else if (c == '\n') 
        { 
         // LF found, finished reading the string 
         return currentLine.ToString(); 
        } 
        else 
        { 
         // If CR was found before , but the next character is not LF, 
         // adding previously skipped CR to the result string 
         currentLine.Append('\r'); 
         foundCR = false; 
        } 
       } 
       else // CR not found 
       { 
        if (c == '\r') 
        { 
         foundCR = true; 
         continue; 
        } 
       } 

       currentLine.Append((char)c); 
       if (currentLine.Length > maxLineLength) 
       { 
        throw new InvalidOperationException("Max line length exceeded"); 
       } 
      } 

      if (foundCR) 
      { 
       // If CR was found before, and the end of the stream has been reached, appending the skipped CR character 
       currentLine.Append('\r'); 
      } 

      if (readData) 
      { 
       return currentLine.ToString(); 
      } 

      // End of the stream reached 
      return null; 

     } 
    } 
} 

Se proporciona esta pieza de código "tal cual" sin garantía.

Cuestiones relacionadas