Advertisement
Guest User

Untitled

a guest
Mar 15th, 2012
238
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 9.96 KB | None | 0 0
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;
  4. using System.Net.Sockets;
  5. using System.Net;
  6. using System.Threading;
  7. using System.Text.RegularExpressions;
  8. using System.IO;
  9.  
  10. namespace HTTPServer
  11. {
  12.     // Класс-обработчик клиента
  13.     class Client
  14.     {
  15.         // Отправка страницы с ошибкой
  16.         private void SendError(TcpClient Client, int Code)
  17.         {
  18.             // Получаем строку вида "200 OK"
  19.             // HttpStatusCode хранит в себе все статус-коды HTTP/1.1
  20.             string CodeStr = Code.ToString() + " " + ((HttpStatusCode)Code).ToString();
  21.             // Код простой HTML-странички
  22.             string Html = "<html><body><h1>" + CodeStr + "</h1></body></html>";
  23.             // Необходимые заголовки: ответ сервера, тип и длина содержимого. После двух пустых строк - само содержимое
  24.             string Str = "HTTP/1.1 " + CodeStr + "\nContent-type: text/html\nContent-Length:" + Html.Length.ToString() + "\n\n" + Html;
  25.             // Приведем строку к виду массива байт
  26.             byte[] Buffer = Encoding.ASCII.GetBytes(Str);
  27.             // Отправим его клиенту
  28.             Client.GetStream().Write(Buffer, 0, Buffer.Length);
  29.             // Закроем соединение
  30.             Client.Close();
  31.         }
  32.  
  33.         // Конструктор класса. Ему нужно передавать принятого клиента от TcpListener
  34.         public Client(TcpClient Client)
  35.         {
  36.             // Объявим строку, в которой будет хранится запрос клиента
  37.             string Request = "";
  38.             // Буфер для хранения принятых от клиента данных
  39.             byte[] Buffer = new byte[1024];
  40.             // Переменная для хранения количества байт, принятых от клиента
  41.             int Count;
  42.             // Читаем из потока клиента до тех пор, пока от него поступают данные
  43.             while ((Count = Client.GetStream().Read(Buffer, 0, Buffer.Length)) > 0)
  44.             {
  45.                 // Преобразуем эти данные в строку и добавим ее к переменной Request
  46.                 Request += Encoding.ASCII.GetString(Buffer, 0, Count);
  47.                 // Запрос должен обрываться последовательностью \r\n\r\n
  48.                 // Либо обрываем прием данных сами, если длина строки Request превышает 4 килобайта
  49.                 // Нам не нужно получать данные из POST-запроса (и т. п.), а обычный запрос
  50.                 // по идее не должен быть больше 4 килобайт
  51.                 if (Request.IndexOf("\r\n\r\n") >= 0 || Request.Length > 4096)
  52.                 {
  53.                     break;
  54.                 }
  55.             }
  56.  
  57.             // Парсим строку запроса с использованием регулярных выражений
  58.             // При этом отсекаем все переменные GET-запроса
  59.             Match ReqMatch = Regex.Match(Request, @"^\w+\s+([^\s\?]+)[^\s]*\s+HTTP/.*|");
  60.  
  61.             // Если запрос не удался
  62.             if (ReqMatch == Match.Empty)
  63.             {
  64.                 // Передаем клиенту ошибку 400 - неверный запрос
  65.                 SendError(Client, 400);
  66.                 return;
  67.             }
  68.  
  69.             // Получаем строку запроса
  70.             string RequestUri = ReqMatch.Groups[1].Value;
  71.  
  72.             // Приводим ее к изначальному виду, преобразуя экранированные символы
  73.             // Например, "%20" -> " "
  74.             RequestUri = Uri.UnescapeDataString(RequestUri);
  75.  
  76.             // Если в строке содержится двоеточие, передадим ошибку 400
  77.             // Это нужно для защиты от URL типа http://example.com/../../file.txt
  78.             if (RequestUri.IndexOf("..") >= 0)
  79.             {
  80.                 SendError(Client, 400);
  81.                 return;
  82.             }
  83.  
  84.             // Если строка запроса оканчивается на "/", то добавим к ней index.html
  85.             if (RequestUri.EndsWith("/"))
  86.             {
  87.                 RequestUri += "index.html";
  88.             }
  89.  
  90.             string FilePath = "www/" + RequestUri;
  91.  
  92.             // Если в папке www не существует данного файла, посылаем ошибку 404
  93.             if (!File.Exists(FilePath))
  94.             {
  95.                 SendError(Client, 404);
  96.                 return;
  97.             }
  98.  
  99.             // Получаем расширение файла из строки запроса
  100.             string Extension = RequestUri.Substring(RequestUri.LastIndexOf('.'));
  101.  
  102.             // Тип содержимого
  103.             string ContentType = "";
  104.  
  105.             // Пытаемся определить тип содержимого по расширению файла
  106.             switch (Extension)
  107.             {
  108.                 case ".htm":
  109.                 case ".html":
  110.                     ContentType = "text/html";
  111.                     break;
  112.                 case ".css":
  113.                     ContentType = "text/stylesheet";
  114.                     break;
  115.                 case ".js":
  116.                     ContentType = "text/javascript";
  117.                     break;
  118.                 case ".jpg":
  119.                     ContentType = "image/jpeg";
  120.                     break;
  121.                 case ".jpeg":
  122.                 case ".png":
  123.                 case ".gif":
  124.                     ContentType = "image/" + Extension.Substring(1);
  125.                     break;
  126.                 default:
  127.                     if (Extension.Length > 1)
  128.                     {
  129.                         ContentType = "application/" + Extension.Substring(1);
  130.                     }
  131.                     else
  132.                     {
  133.                         ContentType = "application/unknown";
  134.                     }
  135.                     break;
  136.             }
  137.  
  138.             // Открываем файл, страхуясь на случай ошибки
  139.             FileStream FS;
  140.             try
  141.             {
  142.                 FS = new FileStream(FilePath, FileMode.Open, FileAccess.Read, FileShare.Read);
  143.             }
  144.             catch (Exception)
  145.             {
  146.                 // Если случилась ошибка, посылаем клиенту ошибку 500
  147.                 SendError(Client, 500);
  148.                 return;
  149.             }
  150.  
  151.             // Посылаем заголовки
  152.             string Headers = "HTTP/1.1 200 OK\nContent-Type: " + ContentType + "\nContent-Length: " + FS.Length + "\n\n";
  153.             byte[] HeadersBuffer = Encoding.ASCII.GetBytes(Headers);
  154.             Client.GetStream().Write(HeadersBuffer, 0, HeadersBuffer.Length);
  155.  
  156.             // Пока не достигнут конец файла
  157.             while (FS.Position < FS.Length)
  158.             {
  159.                 // Читаем данные из файла
  160.                 Count = FS.Read(Buffer, 0, Buffer.Length);
  161.                 // И передаем их клиенту
  162.                 Client.GetStream().Write(Buffer, 0, Count);
  163.             }
  164.  
  165.             // Закроем файл и соединение
  166.             FS.Close();
  167.             Client.Close();
  168.         }
  169.     }
  170.  
  171.     class Server
  172.     {
  173.         Thread ThreadStart;
  174.         TcpListener Listener; // Объект, принимающий TCP-клиентов
  175.         int Port;
  176.         // Запуск сервера
  177.         public Server(int Port1)
  178.         {
  179.             Port = Port1;
  180.         }
  181.  
  182.         public void start()
  183.         {
  184.             Listener = new TcpListener(IPAddress.Any, Port); // Создаем "слушателя" для указанного порта
  185.             ThreadStart = new Thread(new ThreadStart(Listen));
  186.             ThreadStart.Start();
  187.  
  188.            
  189.         }
  190.  
  191.         private void Listen()
  192.         {
  193.             Listener.Start(); // Запускаем его
  194.  
  195.             // В бесконечном цикле
  196.             while (true)
  197.             {
  198.  
  199.  
  200.                
  201.                 // Принимаем нового клиента
  202.                 TcpClient Client = Listener.AcceptTcpClient();
  203.                 // Создаем поток
  204.                 Thread Thread = new Thread(new ParameterizedThreadStart(ClientThread));
  205.                 // И запускаем этот поток, передавая ему принятого клиента
  206.                 Thread.Start(Client);
  207.  
  208.             }
  209.         }
  210.         static void ClientThread(Object StateInfo)
  211.         {
  212.             // Просто создаем новый экземпляр класса Client и передаем ему приведенный к классу TcpClient объект StateInfo
  213.             new Client((TcpClient)StateInfo);
  214.         }
  215.  
  216.         // Остановка сервера
  217.         ~Server()
  218.         {
  219.             // Если "слушатель" был создан
  220.             if (Listener != null)
  221.             {
  222.                 // Остановим его
  223.                 Listener.Stop();
  224.             }
  225.         }
  226.  
  227.         static void Main(string[] args)
  228.         {
  229.            
  230.             // Создадим новый сервер на порту 80
  231.             Server a = new Server(17565);
  232.             a.start();
  233.             Console.ReadKey();
  234.         }
  235.     }
  236. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement