Пример 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 #include <windows.h> #include <winsock.h> #include <stdio.h> #define MAX_INPUT_BUFFER_SIZE 4096 #define MAX_HTTP_LINES 256 #define MAX_DEFAULT_PAGES 16 #define SERVERNAME "Small http v1.0" typedef struct { WORD HttpPort; WORD MaxThreads; CHAR ServerRoot[MAX_PATH]; CHAR DocumentRoot[MAX_PATH]; CHAR DefaultPages[MAX_DEFAULT_PAGES][MAX_PATH]; CHAR SSIExtensions[MAX_PATH]; CHAR ServerName[MAX_PATH]; } TServerConfig; TServerConfig CONF; // Работа с файлом конфигурации int AddDefaultPage(char * name) { int i; for (i = 0; i < MAX_DEFAULT_PAGES; i++) { if (CONF.DefaultPages[i][0] == '\0') { strcpy(CONF.DefaultPages[i], name); return 1; } } printf("Limit of %d default pages exceeded.\n", MAX_DEFAULT_PAGES); return 0; } void SetDefaultPages(char * name) { char * tmp = strtok(name, "\t "); while (tmp) { if (AddDefaultPage(tmp) == 0) break; tmp = strtok(NULL, "\t "); } } void ConfigureServer(void) { char tempstring[MAX_PATH]; FILE * in; memset(&CONF, 0, sizeof(CONF)); GetCurrentDirectory(MAX_PATH - 1, CONF.ServerRoot); CONF.HttpPort = 80; CONF.MaxThreads = 64; strcpy(tempstring, CONF.ServerRoot); if (tempstring[strlen(tempstring) - 1] != '\\') strcat(tempstring, "\\"); strcat(tempstring,"http.conf"); if ((in = fopen(tempstring, "rt")) == NULL) panic("Can not open config file"); while (!feof(in)) { char * param; char * value; memset(tempstring, 0, MAX_PATH); getfileline(tempstring, in); if (feof(in)) break; param = strtok(tempstring, "\t "); value = strtok(NULL, ""); if (!param) continue; if (param[0] == '#') continue; if (stricmp(param, "ServerRoot") == 0) strcpy(CONF.ServerRoot, value); else if (stricmp(param, "DocumentRoot") == 0) strcpy(CONF.DocumentRoot, value); else if (stricmp(param, "ServerPort") == 0) CONF.HttpPort = atoi(value); else if (stricmp(param, "DefaultPages") == 0) SetDefaultPages(value); else if (stricmp(param, "AllowSSI") == 0) strcpy(CONF.SSIExtensions, value); else if (stricmp(param, "ServerName") == 0) strcpy(CONF.ServerName, value); else printf("Unknown option in config file \"%s\"\n", param); } fclose(in); } //Обработка запросов DWORD WINAPI HandleHTTPSession(SOCKET sck); void panic(LPSTR msg); DWORD WINAPI httpdHandler(SOCKET sck); void ConfigureServer(void); char * getmimetype(char *filename); void getfileline(char *line, FILE *in); int IsDir(char * rootdir, char * name); int FileExists(char * rootdir, char * name); static char * FindInHeader(char * * lines, int count, char * param) { int pl = strlen(param); int i; for (i = 0; i < count; i++) { if (strstr(lines[i], param) == lines[i]) return lines[i] + pl; } return 0; } DWORD htSendFile(SOCKET sck, char * rootdir, char * name) { char filename[MAX_PATH]; char tempstr[MAX_PATH]; int numbytes; FILE * in; sprintf(filename, "%s/%s", rootdir, name); if ((in = fopen(filename, "rb")) == NULL) return -1; fseek(in, 0, SEEK_END); if (send(sck, "HTTP/1.1 200 OK\n", 16, 0) == -1) { fclose(in); return -1; } if (send(sck, "Server: "SERVERNAME"\n", strlen("Server: "SERVERNAME"\n"), 0) == -1) { fclose(in); return -1; } sprintf(tempstr, "Content-Length: %d\n", ftell(in)); if (send(sck, tempstr, strlen(tempstr), 0) == -1) { fclose(in); return -1; } sprintf(tempstr, "Content-Type: %s\n\n", getmimetype(filename)); if (send(sck, tempstr, strlen(tempstr), 0) == -1) { fclose(in); return -1; } fseek(in, 0, SEEK_SET); while (!feof(in)) { numbytes = fread(tempstr, 1, sizeof(tempstr), in); if (send(sck, tempstr, numbytes, 0) == -1) { fclose(in); return -1; } } fclose(in); return 0; } DWORD htHandleGET(SOCKET sck, char **lines, int numlines, char * request, char * proto) { /* GET запрос */ char * file = strtok(request, "?"); char * qry = strtok(NULL, ""); if (strstr(file, "/..") || file[0] == '\0') return htSendFile(sck, CONF.ServerRoot, "errors/404.htm"); if (file[strlen(file) - 1] == '/') { /* индексный файл */ int i = 0; while (CONF.DefaultPages[i][0] != '\0') { if (FileExists(CONF.DocumentRoot, CONF.DefaultPages[i])) return htSendFile(sck, CONF.DocumentRoot, CONF.DefaultPages[i]); i++; } } else { /* файл */ if (FileExists(CONF.DocumentRoot, file)) return htSendFile(sck, CONF.DocumentRoot, file); } return htSendFile(sck, CONF.ServerRoot, "errors/404.htm"); } DWORD htHandleHEAD(SOCKET sck, char **lines, int numlines, char * file, char * proto) { /* Запрос HEAD заголовка */ return htSendFile(sck, CONF.ServerRoot, "errors/error_in_cms.htm"); } DWORD htHandlePOST(SOCKET sck, char **lines, int numlines, char * file, char * proto) { /* Запрос HEAD заголовка */ return htSendFile(sck, CONF.ServerRoot, "errors/error_in_cms.htm"); } DWORD WINAPI HandleHTTPSession(SOCKET sck) { char inbuffer[MAX_INPUT_BUFFER_SIZE]; char * lines[MAX_HTTP_LINES]; char * str, * file, *proto; int numbytes = 0; int numlines = 0; memset(inbuffer, 0, MAX_INPUT_BUFFER_SIZE); while(!strstr(inbuffer, "\r\n\r\n") && !strstr(inbuffer, "\n\n")) { int scratch = recv(sck, inbuffer + numbytes, MAX_INPUT_BUFFER_SIZE - numbytes, 0); if (scratch == -1) return 0; numbytes += scratch; if (numbytes == MAX_INPUT_BUFFER_SIZE) { //Переполнение буфера return 0; } } str = strtok(inbuffer, "\r\n"); while(str) { lines[numlines++] = str; str = strtok(NULL, "\r\n"); } str = strtok(lines[0], " "); if (str == NULL) return htSendFile(sck, CONF.ServerRoot, "errors/error_in_cms.htm"); file = strtok(NULL, " "); proto = strtok(NULL, " "); if (!strcmp(str, "GET")) return htHandleGET(sck, lines, numlines, file, proto); else if (!strcmp(str, "HEAD")) return htHandleHEAD(sck, lines, numlines, file, proto); else if (!strcmp(str, "POST")) return htHandlePOST(sck, lines, numlines, file, proto); return htSendFile(sck, CONF.ServerRoot, "errors/error_in_cms.htm"); }
|