Advertisement
Golden_Rus

Mini useless web server

Feb 24th, 2017
111
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 11.03 KB | None | 0 0
  1. ////////////////MHTTPsrv.cpp///////////////////////////////////////
  2. // MHTTPsrv.cpp: определяет точку входа для консольного приложения.
  3. //
  4.  
  5. #include "stdafx.h"
  6. #include "MHTTPsrv.h"
  7.  
  8. #ifdef _DEBUG
  9. #define new DEBUG_NEW
  10. #endif
  11.  
  12.  
  13. // Единственный объект приложения
  14.  
  15. CWinApp theApp;
  16.  
  17. using namespace std;
  18. #include <iostream>
  19. #include <sstream>
  20. #include <string>
  21. #include <fstream>
  22. #include <io.h>
  23.  
  24. // Для корректной работы freeaddrinfo в MinGW
  25. // Подробнее: http://stackoverflow.com/a/20306451
  26. #define _WIN32_WINNT 0x501
  27.  
  28. #include <WinSock2.h>
  29. #include <WS2tcpip.h>
  30.  
  31. // Необходимо, чтобы линковка происходила с DLL-библиотекой
  32. // Для работы с сокетам
  33. #pragma comment(lib, "Ws2_32.lib")
  34.  
  35. #include <regex>  
  36. #include "get_req.h"
  37.  
  38. using std::cerr;
  39.  
  40.  
  41. bool senddata(SOCKET sock, void *buf, int buflen)
  42. {
  43.     const char *pbuf = (const char *)buf;
  44.  
  45.     while (buflen > 0)
  46.     {
  47.         int num = send(sock, pbuf, buflen, 0);
  48.         if (num == SOCKET_ERROR)
  49.         {
  50.             if (WSAGetLastError() == WSAEWOULDBLOCK)
  51.             {
  52.                 // optional: use select() to check for timeout to fail the send
  53.                 continue;
  54.             }
  55.             return false;
  56.         }
  57.  
  58.         pbuf += num;
  59.         buflen -= num;
  60.     }
  61.  
  62.     return true;
  63. }
  64.  
  65. bool sendlong(SOCKET sock, long value)
  66. {
  67.     value = htonl(value);
  68.     return senddata(sock, &value, sizeof(value));
  69. }
  70.  
  71. bool sendfile(SOCKET sock, FILE *f)
  72. {
  73.     fseek(f, 0, SEEK_END);
  74.     long filesize = ftell(f);
  75.     rewind(f);
  76.     if (filesize == EOF)
  77.         return false;
  78.     if (!sendlong(sock, filesize))
  79.         return false;
  80.     if (filesize > 0)
  81.     {
  82.         char buffer[1024];
  83.         do
  84.         {
  85.             size_t num = min(filesize, sizeof(buffer));
  86.             num = fread(buffer, 1, num, f);
  87.             if (num < 1)
  88.                 return false;
  89.             if (!senddata(sock, buffer, num))
  90.                 return false;
  91.             filesize -= num;
  92.         } while (filesize > 0);
  93.     }
  94.     return true;
  95. }
  96.  
  97. int main()
  98. {
  99.  
  100.  
  101.     int nRetCode = 0;
  102.  
  103.     HMODULE hModule = ::GetModuleHandle(nullptr);
  104.  
  105.     if (hModule != nullptr)
  106.     {
  107.         // инициализировать MFC, а также печать и сообщения об ошибках про сбое
  108.         if (!AfxWinInit(hModule, nullptr, ::GetCommandLine(), 0))
  109.         {
  110.             // TODO: измените код ошибки соответственно своим потребностям
  111.             wprintf(L"Критическая ошибка: сбой при инициализации MFC\n");
  112.             nRetCode = 1;
  113.         }
  114.         else
  115.         {
  116.             WSADATA wsaData; // служебная структура для хранение информации
  117.                              // о реализации Windows Sockets
  118.                              // старт использования библиотеки сокетов процессом
  119.                              // (подгружается Ws2_32.dll)
  120.             int result = WSAStartup(MAKEWORD(2, 2), &wsaData);
  121.  
  122.             // Если произошла ошибка подгрузки библиотеки
  123.             if (result != 0) {
  124.                 cerr << "WSAStartup failed: " << result << "\n";
  125.                 return result;
  126.             }
  127.  
  128.             struct addrinfo* addr = NULL; // структура, хранящая информацию
  129.                                           // об IP-адресе  слущающего сокета
  130.  
  131.                                           // Шаблон для инициализации структуры адреса
  132.             struct addrinfo hints;
  133.             ZeroMemory(&hints, sizeof(hints));
  134.  
  135.             hints.ai_family = AF_INET; // AF_INET определяет, что будет
  136.                                        // использоваться сеть для работы с сокетом
  137.             hints.ai_socktype = SOCK_STREAM; // Задаем потоковый тип сокета
  138.             hints.ai_protocol = IPPROTO_TCP; // Используем протокол TCP
  139.             hints.ai_flags = AI_PASSIVE; // Сокет будет биндиться на адрес,
  140.                                          // чтобы принимать входящие соединения
  141.  
  142.                                          // Инициализируем структуру, хранящую адрес сокета - addr
  143.                                          // Наш HTTP-сервер будет висеть на 8000-м порту локалхоста
  144.             result = getaddrinfo("127.0.0.1", "8000", &hints, &addr);
  145.  
  146.             // Если инициализация структуры адреса завершилась с ошибкой,
  147.             // выведем сообщением об этом и завершим выполнение программы
  148.             if (result != 0) {
  149.                 cerr << "getaddrinfo failed: " << result << "\n";
  150.                 WSACleanup(); // выгрузка библиотеки Ws2_32.dll
  151.                 return 1;
  152.             }
  153.  
  154.             // Создание сокета
  155.             int listen_socket = socket(addr->ai_family, addr->ai_socktype,
  156.                 addr->ai_protocol);
  157.             // Если создание сокета завершилось с ошибкой, выводим сообщение,
  158.             // освобождаем память, выделенную под структуру addr,
  159.             // выгружаем dll-библиотеку и закрываем программу
  160.             if (listen_socket == INVALID_SOCKET) {
  161.                 cerr << "Error at socket: " << WSAGetLastError() << "\n";
  162.                 freeaddrinfo(addr);
  163.                 WSACleanup();
  164.                 return 1;
  165.             }
  166.  
  167.             // Привязываем сокет к IP-адресу
  168.             result = bind(listen_socket, addr->ai_addr, (int)addr->ai_addrlen);
  169.  
  170.             // Если привязать адрес к сокету не удалось, то выводим сообщение
  171.             // об ошибке, освобождаем память, выделенную под структуру addr.
  172.             // и закрываем открытый сокет.
  173.             // Выгружаем DLL-библиотеку из памяти и закрываем программу.
  174.             if (result == SOCKET_ERROR) {
  175.                 cerr << "bind failed with error: " << WSAGetLastError() << "\n";
  176.                 freeaddrinfo(addr);
  177.                 closesocket(listen_socket);
  178.                 WSACleanup();
  179.                 return 1;
  180.             }
  181.  
  182.             // Инициализируем слушающий сокет
  183.             if (listen(listen_socket, SOMAXCONN) == SOCKET_ERROR) {
  184.                 cerr << "listen failed with error: " << WSAGetLastError() << "\n";
  185.                 closesocket(listen_socket);
  186.                 WSACleanup();
  187.                 return 1;
  188.             }
  189.  
  190.  
  191.             const int max_client_buffer_size = 1024;
  192.             char buf[max_client_buffer_size];
  193.             int client_socket = INVALID_SOCKET;
  194.  
  195.             for (;;) {
  196.                 // Принимаем входящие соединения
  197.                 client_socket = accept(listen_socket, NULL, NULL);
  198.                 if (client_socket == INVALID_SOCKET) {
  199.                     cerr << "accept failed: " << WSAGetLastError() << "\n";
  200.                     closesocket(listen_socket);
  201.                     WSACleanup();
  202.                     return 1;
  203.                 }
  204.  
  205.                 result = recv(client_socket, buf, max_client_buffer_size, 0);
  206.  
  207.                 std::stringstream response; // сюда будет записываться ответ клиенту
  208.                 std::stringstream response_body; // тело ответа
  209.  
  210.                 if (result == SOCKET_ERROR) {
  211.                     // ошибка получения данных
  212.                     cerr << "recv failed: " << result << "\n";
  213.                     closesocket(client_socket);
  214.                 }
  215.                 else if (result == 0) {
  216.                     // соединение закрыто клиентом
  217.                     cerr << "connection closed...\n";
  218.                 }
  219.                 else if (result > 0) {
  220.                     // Мы знаем фактический размер полученных данных, поэтому ставим метку конца строки
  221.                     // В буфере запроса.
  222.                     buf[result] = '\0';
  223.  
  224.                     // Данные успешно получены
  225.                     // формируем тело ответа (HTML
  226.                     std::string line;
  227.                     line = string(buf);
  228.                     get_req req;
  229.                     req.get_patch(line);
  230.                     line = "." + line;
  231.                     cerr << "File "<<line<<"\n";
  232.                     if (req.get_exp(line) == "html")
  233.                     {
  234.                         std::ifstream file;
  235.                         file.open(line);
  236.                         if (file)
  237.                         {
  238.                             while (file)
  239.                             {
  240.                                 std::string str;
  241.                                 std::getline(file, str);
  242.                                 response_body << str << "\n";
  243.                             }
  244.                             file.close();
  245.                         }
  246.                         else
  247.                         {
  248.                             response_body << "File not found\n";
  249.                             cerr << "File " << line << " not found\n";
  250.                         }
  251.                         // Формируем весь ответ вместе с заголовками
  252.                         response << "HTTP/1.1 200 OK\r\n"
  253.                             << "Version: HTTP/1.1\r\n"
  254.                             << "Content-Type: text/html; charset=utf-8\r\n"
  255.                             << "Content-Length: " << response_body.str().length()
  256.                             << "\r\n\r\n"
  257.                             << response_body.str();
  258.  
  259.                         // Отправляем ответ клиенту с помощью функции send
  260.                         result = send(client_socket, response.str().c_str(),
  261.                             response.str().length(), 0);
  262.                     }
  263.                     else
  264.                     {
  265.                         cerr << "Send binary file " << line << "\n";
  266.                         FILE *filehandle = fopen(line.c_str(), "rb");
  267.                         if (filehandle != NULL)
  268.                         {
  269.                             sendfile(client_socket, filehandle);
  270.                             fclose(filehandle);
  271.                         }
  272.                     }
  273.  
  274.                     if (result == SOCKET_ERROR) {
  275.                         // произошла ошибка при отправле данных
  276.                         cerr << "send failed: " << WSAGetLastError() << "\n";
  277.                     }
  278.                     // Закрываем соединение к клиентом
  279.                     closesocket(client_socket);
  280.                 }
  281.             }
  282.  
  283.             // Убираем за собой
  284.             closesocket(listen_socket);
  285.             freeaddrinfo(addr);
  286.             WSACleanup();
  287.             return 0;
  288.         }
  289.     }
  290.     else
  291.     {
  292.         // TODO: Измените код ошибки соответственно своим потребностям
  293.         wprintf(L"Критическая ошибка: неудачное завершение GetModuleHandle\n");
  294.         nRetCode = 1;
  295.     }
  296.  
  297.     return nRetCode;
  298. }
  299. ///////////////////get_req.cpp///////////////////////////////////////////////////////
  300. #include "stdafx.h"
  301. #include "get_req.h"
  302. #include <vector>
  303.  
  304. get_req::get_req()
  305. {
  306. }
  307.  
  308. std::string get_req::get_patch(std::string &req)
  309. {
  310.     std::vector<std::string> patch;
  311.     char *tmp = new char[req.length() + 1];
  312.     strcpy(tmp, req.c_str());
  313.     char * pch = strtok(tmp, " "); // во втором параметре указаны разделитель (пробел, запятая, точка, тире)
  314.  
  315.     while (pch != NULL)                         // пока есть лексемы
  316.     {
  317.         patch.push_back(pch);
  318.         pch = strtok(NULL, " ");
  319.     }
  320.     req = patch[1];
  321.     return patch[1];
  322. }
  323.  
  324. std::string get_req::get_exp(std::string & req)
  325. {
  326.     std::vector<std::string> patch;
  327.     char *tmp = new char[req.length() + 1];
  328.     strcpy(tmp, req.c_str());
  329.     char * pch = strtok(tmp, "."); // во втором параметре указаны разделитель (пробел, запятая, точка, тире)
  330.  
  331.     while (pch != NULL)                         // пока есть лексемы
  332.     {
  333.         patch.push_back(pch);
  334.         pch = strtok(NULL, ".");
  335.     }
  336.     return patch.back();
  337. }
  338. ///////////////////////////get_req.h////////////////////////
  339. #pragma once
  340. class get_req
  341. {
  342. public:
  343.     get_req();
  344.     std::string get_patch(std::string &req);
  345.     std::string get_exp(std::string &req);
  346. private:
  347.     std::string input;
  348. };
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement