Пример http сервера на Си(C++) Windows Api


Добавил:DMT
Дата создания:29 апреля 2008, 22:51
Дата обновления:30 апреля 2008, 2:08
Просмотров:26259 последний сегодня, 11:38
Комментариев: 0
Пример http сервера, как написать http сервер?.

Hypertext Transfer Protocol (HTTP, протокол пересылки гипертекста) - это язык, которым клиенты и серверы World Wide Web пользуются для общения между собой. Он, по сути дела, является основой в Web.

Обращаясь к какому нибудь сайту, Вы просматриваете содержимое страницы которую вам присылает сервер используя протокол HTTP. Сервер обрабатывает Ваш запрос, запрос Вашего браузера и выполняет действия заложенные в запросе. А как написать сам сервер?? Предлагаем вариант написания HTTP сервера используя функции ОС Windows работы с сокетами.

Файлы:
errors/error_in_cms.htm - ошибка команды
errors/404.htm - ошибка отсутствие файла

Содержимое файла http.conf:
ServerRoot C:\http
ServerPort 80
DocumentRoot C:\http\site_name
DefaultPages index.htm index.html

Код на ASM
  1. #include <windows.h>
  2. #include <winsock.h>
  3. #include <stdio.h>
  4.  
  5. #define MAX_INPUT_BUFFER_SIZE 4096
  6. #define MAX_HTTP_LINES 256
  7. #define MAX_DEFAULT_PAGES 16
  8. #define SERVERNAME "Small http v1.0"
  9.  
  10. typedef struct {
  11. WORD HttpPort;
  12. WORD MaxThreads;
  13. CHAR ServerRoot[MAX_PATH];
  14. CHAR DocumentRoot[MAX_PATH];
  15. CHAR DefaultPages[MAX_DEFAULT_PAGES][MAX_PATH];
  16. CHAR SSIExtensions[MAX_PATH];
  17. CHAR ServerName[MAX_PATH];
  18. } TServerConfig;
  19.  
  20. TServerConfig CONF;
  21.  
  22. // Работа с файлом конфигурации
  23. int AddDefaultPage(char * name)
  24. {
  25. int i;
  26.  
  27. for (i = 0; i < MAX_DEFAULT_PAGES; i++)
  28. {
  29. if (CONF.DefaultPages[i][0] == '\0')
  30. {
  31. strcpy(CONF.DefaultPages[i], name);
  32. return 1;
  33. }
  34. }
  35.  
  36. printf("Limit of %d default pages exceeded.\n", MAX_DEFAULT_PAGES);
  37. return 0;
  38. }
  39.  
  40. void SetDefaultPages(char * name)
  41. {
  42. char * tmp = strtok(name, "\t ");
  43.  
  44. while (tmp)
  45. {
  46. if (AddDefaultPage(tmp) == 0) break;
  47. tmp = strtok(NULL, "\t ");
  48. }
  49. }
  50.  
  51. void ConfigureServer(void)
  52. {
  53. char tempstring[MAX_PATH];
  54. FILE * in;
  55.  
  56. memset(&CONF, 0, sizeof(CONF));
  57.  
  58. GetCurrentDirectory(MAX_PATH - 1, CONF.ServerRoot);
  59. CONF.HttpPort = 80;
  60. CONF.MaxThreads = 64;
  61.  
  62. strcpy(tempstring, CONF.ServerRoot);
  63.  
  64. if (tempstring[strlen(tempstring) - 1] != '\\')
  65. strcat(tempstring, "\\");
  66.  
  67. strcat(tempstring,"http.conf");
  68. if ((in = fopen(tempstring, "rt")) == NULL)
  69. panic("Can not open config file");
  70.  
  71. while (!feof(in))
  72. {
  73. char * param;
  74. char * value;
  75.  
  76. memset(tempstring, 0, MAX_PATH);
  77. getfileline(tempstring, in);
  78.  
  79. if (feof(in)) break;
  80.  
  81. param = strtok(tempstring, "\t ");
  82. value = strtok(NULL, "");
  83.  
  84. if (!param) continue;
  85. if (param[0] == '#') continue;
  86.  
  87. if (stricmp(param, "ServerRoot") == 0)
  88. strcpy(CONF.ServerRoot, value);
  89. else if (stricmp(param, "DocumentRoot") == 0)
  90. strcpy(CONF.DocumentRoot, value);
  91. else if (stricmp(param, "ServerPort") == 0)
  92. CONF.HttpPort = atoi(value);
  93. else if (stricmp(param, "DefaultPages") == 0)
  94. SetDefaultPages(value);
  95. else if (stricmp(param, "AllowSSI") == 0)
  96. strcpy(CONF.SSIExtensions, value);
  97. else if (stricmp(param, "ServerName") == 0)
  98. strcpy(CONF.ServerName, value);
  99. else
  100. printf("Unknown option in config file \"%s\"\n", param);
  101. }
  102.  
  103. fclose(in);
  104. }
  105.  
  106. //Обработка запросов
  107.  
  108. DWORD WINAPI HandleHTTPSession(SOCKET sck);
  109. void panic(LPSTR msg);
  110. DWORD WINAPI httpdHandler(SOCKET sck);
  111. void ConfigureServer(void);
  112. char * getmimetype(char *filename);
  113. void getfileline(char *line, FILE *in);
  114. int IsDir(char * rootdir, char * name);
  115. int FileExists(char * rootdir, char * name);
  116.  
  117.  
  118. static char * FindInHeader(char * * lines, int count, char * param)
  119. {
  120. int pl = strlen(param);
  121. int i;
  122.  
  123. for (i = 0; i < count; i++)
  124. {
  125. if (strstr(lines[i], param) == lines[i])
  126. return lines[i] + pl;
  127. }
  128.  
  129. return 0;
  130. }
  131.  
  132. DWORD htSendFile(SOCKET sck, char * rootdir, char * name)
  133. {
  134. char filename[MAX_PATH];
  135. char tempstr[MAX_PATH];
  136. int numbytes;
  137. FILE * in;
  138.  
  139. sprintf(filename, "%s/%s", rootdir, name);
  140.  
  141. if ((in = fopen(filename, "rb")) == NULL)
  142. return -1;
  143.  
  144. fseek(in, 0, SEEK_END);
  145.  
  146. if (send(sck, "HTTP/1.1 200 OK\n", 16, 0) == -1)
  147. {
  148. fclose(in);
  149. return -1;
  150. }
  151.  
  152. if (send(sck, "Server: "SERVERNAME"\n", strlen("Server: "SERVERNAME"\n"), 0) == -1)
  153. {
  154. fclose(in);
  155. return -1;
  156. }
  157.  
  158. sprintf(tempstr, "Content-Length: %d\n", ftell(in));
  159. if (send(sck, tempstr, strlen(tempstr), 0) == -1)
  160. {
  161. fclose(in);
  162. return -1;
  163. }
  164.  
  165. sprintf(tempstr, "Content-Type: %s\n\n", getmimetype(filename));
  166. if (send(sck, tempstr, strlen(tempstr), 0) == -1)
  167. {
  168. fclose(in);
  169. return -1;
  170. }
  171.  
  172. fseek(in, 0, SEEK_SET);
  173.  
  174. while (!feof(in))
  175. {
  176. numbytes = fread(tempstr, 1, sizeof(tempstr), in);
  177. if (send(sck, tempstr, numbytes, 0) == -1)
  178. {
  179. fclose(in);
  180. return -1;
  181. }
  182. }
  183.  
  184. fclose(in);
  185.  
  186. return 0;
  187. }
  188.  
  189. DWORD htHandleGET(SOCKET sck, char **lines, int numlines, char * request, char * proto)
  190. {
  191. /* GET запрос */
  192. char * file = strtok(request, "?");
  193. char * qry = strtok(NULL, "");
  194.  
  195. if (strstr(file, "/..") || file[0] == '\0')
  196. return htSendFile(sck, CONF.ServerRoot, "errors/404.htm");
  197.  
  198. if (file[strlen(file) - 1] == '/')
  199. {
  200. /* индексный файл */
  201. int i = 0;
  202. while (CONF.DefaultPages[i][0] != '\0')
  203. {
  204. if (FileExists(CONF.DocumentRoot, CONF.DefaultPages[i]))
  205. return htSendFile(sck, CONF.DocumentRoot, CONF.DefaultPages[i]);
  206. i++;
  207. }
  208. }
  209. else {
  210. /* файл */
  211. if (FileExists(CONF.DocumentRoot, file))
  212. return htSendFile(sck, CONF.DocumentRoot, file);
  213. }
  214.  
  215. return htSendFile(sck, CONF.ServerRoot, "errors/404.htm");
  216. }
  217.  
  218. DWORD htHandleHEAD(SOCKET sck, char **lines, int numlines, char * file, char * proto)
  219. {
  220. /* Запрос HEAD заголовка */
  221. return htSendFile(sck, CONF.ServerRoot, "errors/error_in_cms.htm");
  222. }
  223.  
  224. DWORD htHandlePOST(SOCKET sck, char **lines, int numlines, char * file, char * proto)
  225. {
  226. /* Запрос HEAD заголовка */
  227. return htSendFile(sck, CONF.ServerRoot, "errors/error_in_cms.htm");
  228. }
  229.  
  230. DWORD WINAPI HandleHTTPSession(SOCKET sck)
  231. {
  232. char inbuffer[MAX_INPUT_BUFFER_SIZE];
  233. char * lines[MAX_HTTP_LINES];
  234. char * str, * file, *proto;
  235. int numbytes = 0;
  236. int numlines = 0;
  237.  
  238. memset(inbuffer, 0, MAX_INPUT_BUFFER_SIZE);
  239. while(!strstr(inbuffer, "\r\n\r\n") && !strstr(inbuffer, "\n\n"))
  240. {
  241. int scratch = recv(sck, inbuffer + numbytes, MAX_INPUT_BUFFER_SIZE - numbytes, 0);
  242. if (scratch == -1) return 0;
  243.  
  244. numbytes += scratch;
  245.  
  246. if (numbytes == MAX_INPUT_BUFFER_SIZE)
  247. {
  248. //Переполнение буфера
  249. return 0;
  250. }
  251. }
  252.  
  253. str = strtok(inbuffer, "\r\n");
  254.  
  255. while(str)
  256. {
  257. lines[numlines++] = str;
  258. str = strtok(NULL, "\r\n");
  259. }
  260.  
  261. str = strtok(lines[0], " ");
  262. if (str == NULL)
  263. return htSendFile(sck, CONF.ServerRoot, "errors/error_in_cms.htm");
  264.  
  265. file = strtok(NULL, " ");
  266. proto = strtok(NULL, " ");
  267.  
  268. if (!strcmp(str, "GET"))
  269. return htHandleGET(sck, lines, numlines, file, proto);
  270. else if (!strcmp(str, "HEAD"))
  271. return htHandleHEAD(sck, lines, numlines, file, proto);
  272. else if (!strcmp(str, "POST"))
  273. return htHandlePOST(sck, lines, numlines, file, proto);
  274. return htSendFile(sck, CONF.ServerRoot, "errors/error_in_cms.htm");
  275. }
При использовании обязательна ссылка на http://DMTSoft.ru
up