• B правой части каждого сообщения есть стрелки и . Не стесняйтесь оценивать ответы. Чтобы автору вопроса закрыть свой тикет, надо выбрать лучший ответ. Просто нажмите значок в правой части сообщения.

  • 15 апреля стартует «Курс «SQL-injection Master» ©» от команды The Codeby

    За 3 месяца вы пройдете путь от начальных навыков работы с SQL-запросами к базам данных до продвинутых техник. Научитесь находить уязвимости связанные с базами данных, и внедрять произвольный SQL-код в уязвимые приложения.

    На последнюю неделю приходится экзамен, где нужно будет показать свои навыки, взломав ряд уязвимых учебных сайтов, и добыть флаги. Успешно сдавшие экзамен получат сертификат.

    Запись на курс до 25 апреля. Получить промодоступ ...

Задача: Реализация Модельного веб-сервер

  • Автор темы BashOrgRu
  • Дата начала
B

BashOrgRu

Дали задание, написать модельный веб-сервер без CGI: "Сайты, в которых информация (ресурсы) представляет собой набор файлов (обычно – в формате HTML – т.н. веб-страницы), называются статическими. ". То есть нужно сделать реализация модельного веб-сервера, поддерживающуго описанное ниже подмножество протокола HTTP.
HTTP-запрос
HTTP-запрос отправляется веб-клиентом к веб-серверу и имеет вид:
<заголовок запроса> <конец строки>
<HTTP- заголовок > <конец строки>

<HTTP- заголовок > <конец строки>
< конец строки >
<тело запроса>

Здесь и далее <конец строки> - это символ с кодом 10 (\n).
Структура заголовка запроса имеет вид:
< HTTP -метод> URI HTTP/<версия протокола>

Метод GET
Этот метод используется для запроса содержимого ресурса с
сервера. Файл ресурса определяется URI из запроса. Если URI корректен,
то сервер обязан вернуть содержимое запрашиваемого файла, если это
файл данных.
Примеры заголовков запроса GET:
GET /index.html HTTP/1.1
По этому запросу сервер возвращает текст файла index.html из
домашней директории сервера.

Метод HEAD

HTTP-ответ
Ответ веб-сервера имеет следующую структуру:
<заголовок ответа> <конец строки>
<HTTP- заголовок > <конец строки>

<HTTP- заголовок > <конец строки>
< конец строки >
<тело ответа>

Заголовок ответа выглядит так:
HTTP/<версия протокола> <код состояния> <пояснение>


Заголовок Date

Заголовок Host

Заголовок Referer

Заголовок User-agent

Заголовок Server

Заголовок Content-length

Заголовок Content-type

Заголовок Allow

Заголовок Last-modified

"Рекомендуется начать реализацию с двух простых программ, которые пригодятся при тестировании. Первая программа – «псевдо-сервер», цель которого – запись реальных запросов, посылаемых веб-клиентами например, различными веб-браузерами). Такой сервер должен принять запрос, записать его в лог-файл, выдать ответ с кодом 501 «Not Implemented» и немедленно закрыть соединение. Ответ можно заготовить заранее как текстовый файл и выдавать его в сокет по мере надобности. Сохраненные запросы можно использовать для отладки сервера. Для того, чтобы посылать эти запросы к серверу, понадобится еще одно простое приложение – «псевдо-браузер». Это консольное приложение, которое устанавливает связь с сервером, посылает ему заранее заготовленный запрос (тут-то пригодится «псевдо-сервер», хотя тестовые запросы можно приготовить и «вручную») и записывает ответ сервера."


Прошу помочь хоть какой-нибудь информацией по поводу этого или примеров программ. От нас требуют, чтобы мы уже сдавали этот модельный веб-сервер, хотя ни на лекциях, ни на семинарах мы ещё не дошли до сокетов.
На всякий случай, если я непонятно описал задачу, то присоединяю файл, в котором описано подробно задание, и из этого задания мне надо сделать первый этап.
Заранее блогадарен.
 

Вложения

  • httpserver.pdf
    288,7 КБ · Просмотры: 321
D

DarkKnight

В сокетах есть чудесная функция select(), она создает создает множесто, в которых указанны сокеты, 3 множества, 1-ое которые должны прочесть, 2-ое в которые должны записать, и 3ие - которые проверям на ошибки (ну его использовать не нужно)
И конечно же нужно сокеты перевести в не-блокирующее состояние, в этом тебе поможет
fcntl(ТУТ ДЕСКРИТОР ТВОЕГО СОКЕТА, F_SETFL, O_NONBLOCK);
 
B

BashOrgRu

Обрабатывает запросы вроде верно, если подкинуть сайт в html, то откроет как надо, но если ей подсунуть gif-ку, то почему-то откызвается её показывать браузер, хотя в логах видно, что сервер посылает её браузеру.


C++:
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/stat.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <locale.h>
#include <time.h>
#include <string.h>
#include <signal.h>

struct word
{
char *cont;
struct word *next;
};

int Lok;
char Allow[]="Allow: GET,HEAD\n\0",
ServerN[]="Server: Model HTTP Server/0.1\n\0";
char LastM[50];

struct word *CreatList(char *str, int Count)
{
int i=0,is=-1,j,mark=0,k,p;
struct word *head,*Elem;

head=(struct word *)malloc(sizeof(struct word));
Elem=head;
while(i!=(Count+1))
{
if ( str[i]==' ' || str[i]=='\n' || i==Count )
{
Elem->cont=malloc((i-is)*sizeof(char));
k=0;
for (j=(is+1); j<i; j++)
{
*((Elem->cont)+k)=str[j];
k++;
}
*((Elem->cont)+k)='\0';
if (i!=Count)
Elem->next=(struct word *)malloc(sizeof(struct word));
else
Elem->next=NULL;
Elem=Elem->next;
is=i;
}
i++;
}
if (!strcmp((head->next)->cont,"/\0")){
head->next->cont=malloc(10*sizeof(char));
sprintf(head->next->cont,"/index.htm");
}
return (head);
}

void SigHndlr(int s){
printf("Заврешение работы.\n");
shutdown(Lok,0);
close(Lok);
signal(SIGINT,SIG_DFL); 
}

char *OpRF(char *name,unsigned long *len)
{
char c;
FILE *fp;
unsigned long int i=0;
if ((fp=fopen(name,"rb"))==NULL)
{
return NULL;
}
fseek(fp,0,SEEK_END);
unsigned long int l;
l=ftell(fp);
*len=l;
char *str=malloc((l+1)*sizeof(char));
i=0;
close(fp);
fp=fopen(name,"rb");
while(!feof(fp))
{
fread(&c,sizeof(char),1,fp);
str[i]=c;
i++;
}
str[i]='\0';
close(fp);
return str;
}

char *GetEx(char *str)
{
int n=strlen(str);
int i,j,k=0,p;

if (strchr(str,'.')!=NULL)
{
for (i=(strlen(str)-1); i>=0; i--)
if (str[i]=='.')
{
j=i;
break;
}
char *ex;
ex=(char *)malloc((n-j)*sizeof(char));
for (i=j+1; i<=n; i++)
{
ex[k]=str[i];
k++;
}
return ex;
}
else return NULL;
}

char *CpS(char *str1,char *str2){
unsigned long i,n=strlen(str2);

for (i=0;i<=n;i++) str1[i]=str2[i];
return str1;
}

char *HeadS(struct word *head,int *CODE)
{
struct tm *Date,*Last;
long timeT,timeL;
char DateS[50],LastS[60];
int i=0;
char *name=(head->next)->cont;
char *exs;
char *type=malloc(26*sizeof(char));
char *http;
struct stat stbuf;

for (i=0; i<strlen(name); i++) name[i]=name[i+1];

char cod[5];
char comm[22];
if (strcmp("GET\0",head->cont) && strcmp("HEAD\0",head->cont))
{
strcpy(cod,"501\0");;
*CODE=501;
strcpy(comm,"Service Unavailable\0");
}
else if (strchr(name,'?')!=NULL)
{
strcpy(cod,"400\0");
*CODE=400;
strcpy(comm,"Syntax error\0");
}
else if (stat(name,&stbuf)==-1)
{
strcpy(cod,"404\0");
*CODE=404;
strcpy(comm,"Not found file\0");
}
else if ((((stbuf.st_mode)>>2)|1)==0) //rwx
{
strcpy(cod,"403\0");
*CODE=403;
strcpy(comm,"Forbidden\0");
}
else
{
strcpy(cod,"200\0");
*CODE=200;
strcpy(comm,"Ok\0");
}
if (!strcmp(head->cont,"GET\0")){
CpS(type,"text/html\0");
if (*CODE==200){
exs=GetEx(name);
if (!strcmp(exs,"jpg\0"))
CpS(type,"image/jpeg\0");
if (!strcmp(exs,"gif\0"))
CpS(type,"image/gif\0");
if (!strcmp(exs,"png\0"))
CpS(type,"image/png\0");
stat(name,&stbuf);
timeL=stbuf.st_mtime;
Last=gmtime(&timeL);
strftime(LastS,50,"Last-modified: %a, %d %b %Y %H:%M:%S GMT",Last);
}
}

time(&timeT);
Date=gmtime(&timeT);
strftime(DateS,50,"Date: %a, %d %b %Y %H:%M:%S GMT",Date);
http=malloc((strlen(cod)+40+strlen(comm)+strlen(DateS)+strlen(type)+strlen(LastS)+strlen(ServerN)+strlen(Allow))*sizeof(char));
if (*CODE==501) sprintf(http,"HTTP/1.1 %s %s\nMIME-version: 1.1\n%s\nContent-Type: %s\n%s\n",cod,comm,DateS,type,Allow);
if (*CODE==200) sprintf(http,"HTTP/1.1 %s %s\nMIME-version: 1.1\n%s\nContent-Type: %s\n%s\n",cod,comm,DateS,type,LastS);
else sprintf(http,"HTTP/1.1 %s %s\nMIME-version: 1.1\n%s\nContent-Type: %s\n",cod,comm,DateS,type);
return http;
}

char *GetBody(struct word *head,int CODE,char *headM,unsigned long *length){
char *str;
unsigned long len;
char *p;

if (CODE==200){
str=OpRF((head->next)->cont,&len);
*length=len;
}
if (CODE==404){
str=malloc((strlen((head->next)->cont)+150)*sizeof(char));
sprintf(str,"<HTML><HEAD><TITLE>ModalServer 1.1b</TITLE></HEAD>\n<BODY>\n<H1>Error 404\n Didn't find: %s</H1>\n</HTML>",(head->next)->cont);
*length=strlen(str)*sizeof(char);
}
if (CODE==400){
str=malloc((strlen((head->next)->cont)+150)*sizeof(char));
sprintf(str,"<HTML><HEAD><TITLE>ModalServer 1.1b</TITLE></HEAD>\n<BODY>\n<H1>Syntax error!</H1>\n</HTML>",(head->next)->cont);
*length=strlen(str)*sizeof(char);
}
if (CODE==403){
str=malloc((strlen((head->next)->cont)+150)*sizeof(char));
sprintf(str,"<HTML><HEAD><TITLE>ModalServer 1.1b</TITLE></HEAD>\n<BODY>\n<H1>Bad request You haven't permission!</H1>\n</HTML>",(head->next)->cont);
*length=strlen(str)*sizeof(char);
}
if (CODE==500){
str=malloc((strlen((head->next)->cont)+150)*sizeof(char));
sprintf(str,"<HTML><HEAD><TITLE>ModalServer 1.1b</TITLE></HEAD>\n<BODY>\n<H1>Forbidden You haven't permission!</H1>\n</HTML>",(head->next)->cont);
*length=strlen(str)*sizeof(char);
}
if (CODE==501){
str=malloc((strlen((head->next)->cont)+150)*sizeof(char));
sprintf(str,"<HTML><HEAD><TITLE>ModalServer 1.1b</TITLE></HEAD>\n<BODY>\n<H1>Not Implemented.</H1>\n</HTML>",(head->next)->cont);
*length=strlen(str)*sizeof(char);
}
if (CODE==503){
str=malloc((strlen((head->next)->cont)+150)*sizeof(char));
sprintf(str,"<HTML><HEAD><TITLE>ModalServer 1.1b</TITLE></HEAD>\n<BODY>\n<H1>Service Unavailable.</H1>\n</HTML>",(head->next)->cont);
*length=strlen(str)*sizeof(char);
}
return str;
}

char *AddCL(char *str,unsigned long len){
char *str1=malloc((35+strlen(ServerN)+strlen(str))*sizeof(char));

sprintf(str1,"%sContent-Length: %li\nServer: Model HTTP Server/0.1\n\n",str,len);
return str1;
}

int main (void)
{
struct word *Sp;
char *str,*HEAD,*sendM;
int CODE,i;
unsigned long len;
int ServerSocket = socket (AF_INET, SOCK_STREAM, 0);
struct sockaddr_in ServerAddress;

ServerAddress.sin_addr.s_addr = INADDR_ANY;
ServerAddress.sin_port = htons(8888);
ServerAddress.sin_family = AF_INET;

if (bind(ServerSocket,(struct sockaddr *)&ServerAddress, sizeof(ServerAddress))<0)
{
printf( "Не могу забиндить \n");
return 0;
}
else printf( "Bind is OK\n");

if (listen(ServerSocket,3) >=0)
printf("Прослушивание выполнено \n");
else return 0;
struct sockaddr_in clAddr;

signal(SIGINT,SigHndlr);
int clAddrLen = sizeof(clAddr);
while (1)
{
int clSocet = accept(ServerSocket,(struct sockaddr *)&clAddr,&clAddrLen);
char Rv[1024];
Lok=clSocet;
memset(Rv,0,1024);
recv(clSocet,Rv,1024,0);
printf( "Запрос к серверу :\n");
printf("%s",Rv);
Sp=CreatList(Rv,strlen(Rv));
HEAD=HeadS(Sp,&CODE);
str=GetBody(Sp,CODE,HEAD,&len);
HEAD=AddCL(HEAD,len);
printf("Отсылаю:\n%s",HEAD);
send(clSocet,HEAD,strlen(HEAD)*sizeof(char),0);
if (!strcmp(Sp->cont,"GET\0"))
send(clSocet,str,strlen(str)*sizeof(char),0);
printf("Ответ послан\n");
printf( "\n------------------------------------------------------------\n");
shutdown(clSocet,0);
close(clSocet);
}
return 0;
}
 
B

BashOrgRu

Спасибо) Вроде как сделал асинхронную обработку запросов, теперь осталось проверить, как это можно сделать?)
 
B

BashOrgRu

DarkKnight125, можешь привести пример с правильно работой функции select и сокетами?
 
B

BashOrgRu

Проблемка с ассинхроностью, если, например, подать серверу на закачку файл размер два мб, то он даст клиенту где-то 2% и всё. Как я понимаю, проблема в том, что с помощью функции select я дожидаюсь сокетов, которые готовы к чтению, но не проверяю их на то, отправили ли они до конца тело сообщения. Как это можно исправить? Если делаю так select(mx+1, &readset, &readset, NULL, NULL), то тогда сервер вообще застывает.
Обработку запроса я опустил, так как она 270 строк кода занимает)


C++:
struct _SocketSet
{
int Sock;
struct _SocketSet *next;
};

struct _SocketSet *DelFrSS(struct _SocketSet *SSetHEAD,int DelSock)
{
struct _SocketSet *prv,*tmp;

for (prv=SSetHEAD; prv!=NULL; prv=prv->next)
{
if (prv->Sock==DelSock)
{
if (prv==SSetHEAD)
{
SSetHEAD=prv->next;
free(prv);
return(SSetHEAD);
}
else
{
tmp->next=prv->next;
free(prv);
return(SSetHEAD);
}
}
tmp=prv;
}
return SSetHEAD;
}

struct _SocketSet *stralloc(int SockEl)
{
struct _SocketSet *SSetElem=(struct _SocketSet *)malloc(sizeof(struct _SocketSet));

SSetElem->Sock=SockEl;
SSetElem->next=NULL;
return SSetElem;
}

struct _SocketSet *AddToSS(struct _SocketSet *SSetHEAD,int AddSock)
{
struct _SocketSet *SSetTMP;

if (SSetHEAD!=NULL)
{
for (SSetTMP=SSetHEAD; SSetTMP->next!=NULL; SSetTMP=SSetTMP->next);
SSetTMP->next=stralloc(AddSock);
}
else SSetHEAD=stralloc(AddSock);
return SSetHEAD;
}

int MaxS(int lis,struct _SocketSet *SSetHEAD)
{
int Max=lis;
struct _SocketSet *SSetTMP;

for (SSetTMP=SSetHEAD; SSetTMP!=NULL; SSetTMP=SSetTMP->next)
if ((SSetTMP->Sock)>Max) Max=SSetTMP->Sock;
return Max;
}

int main()
{
struct word *Sp;
char *str,*HEAD;
int CODE;
unsigned long int len;
int ClSocket;
struct sockaddr_in addr;
struct _SocketSet *SSetHEAD=NULL,*SSetTMP;
char buf[1024];
int bytes_read;


ClSocket = socket(AF_INET, SOCK_STREAM, 0);
if(ClSocket < 0)
{
perror("socket");
exit(1);
}

fcntl(ClSocket, F_SETFL, O_NONBLOCK);

addr.sin_family = AF_INET;
addr.sin_port = htons(8888);
addr.sin_addr.s_addr = INADDR_ANY;
if(bind(ClSocket, (struct sockaddr *)&addr, sizeof(addr)) < 0)
{
perror("bind");
exit(2);
}
else printf("Bind is ok\n");

if (listen(ClSocket, 2)>=0)
{
printf("Прослушивание началось.\n");
}

signal(SIGINT,SigHndlr);
while(1)
{
fd_set readset;
FD_ZERO(&readset);
FD_SET(ClSocket, &readset);

for(SSetTMP=SSetHEAD; SSetTMP!=NULL; SSetTMP=SSetTMP->next)
FD_SET(SSetTMP->Sock,&readset);

int mx = MaxS(ClSocket,SSetHEAD);

if(select(mx+1, &readset, NULL, NULL, NULL) <= 0)
{
}
if(FD_ISSET(ClSocket, &readset))
{
int sock = accept(ClSocket, NULL, NULL);
if(sock < 0)
{
perror("accept");
exit(3);
}

fcntl(sock, F_SETFL, O_NONBLOCK);

SSetHEAD=AddToSS(SSetHEAD,sock);
}

for(SSetTMP=SSetHEAD; SSetTMP!=NULL; SSetTMP=SSetTMP->next)
{
Lock=SSetTMP->Sock;
if(FD_ISSET(SSetTMP->Sock, &readset))
{
bytes_read = recv(SSetTMP->Sock, buf, 1024, 0);
buf[bytes_read]='\0';

if(bytes_read <= 0)
{
shutdown(SSetTMP->Sock,0);
close(SSetTMP->Sock);
SSetHEAD=DelFrSS(SSetHEAD,SSetTMP->Sock);
continue;
}
/*
Обработка запроса. HEAD - ответ на запрос.
*/

send(SSetTMP->Sock,HEAD,strlen(HEAD)*sizeof(char),0);
}
}
}

return 0;
}
 
D

DarkKnight

BashOrg , я извиняюсь неделя долбаная рабочая выдалась, времени вообще не было для форума.... Завтра гляну, найду где ошибка, опишу...
 
Мы в соцсетях:

Обучение наступательной кибербезопасности в игровой форме. Начать игру!