HTTP 1.1 Server своими руками

Тема в разделе "WASM.NETWORKS", создана пользователем skyproc, 10 июл 2009.

  1. skyproc

    skyproc New Member

    Публикаций:
    0
    Регистрация:
    4 май 2007
    Сообщения:
    217
    Вот решил написать мутитредный HTTP server.
    Первые результаты ничего, но к сожалению мало инфы.

    Не ну есть конечно rfc2616 но на английском, половина этого дока есть на русском.
    В общем дело продвигается но не так быстро как хотелось бы.

    Народ если есть у кого полный и корректный перевод rfc2616, статьи и т.п. то плз. оставьте ссылки!

    В часности чёта не понятно как передать клиенту файл по частям???

    Думал вот так:

    _____________________________
    HTTP/1.1 206 Partial Content
    Content-Range: bytes 0-255/257
    Connection: Keep-Alive
    Content-Type: image/jpeg
    Content-Length: 256

    Первая часть файла
    _____________________________



    _____________________________
    HTTP/1.1 200 Ok
    Content-Range: bytes 256-257/257
    Connection: Keep-Alive
    Content-Type: image/jpeg
    Content-Length: 2

    Вторая часть файла
    _____________________________



    но брайзер выводит только первую часть файла и разрывает соединение.
    :dntknw:
     
  2. Folk Acid

    Folk Acid New Member

    Публикаций:
    0
    Регистрация:
    23 авг 2005
    Сообщения:
    432
    Адрес:
    Ukraine
    Держи
    Код (Text):
    1. //==============================================================
    2. // Charlotte - A small Windows web server
    3. //
    4. // Stuart Patterson
    5. //==============================================================
    6. #include <windows.h>
    7. #include <process.h>
    8. #include <iostream>
    9. #include <fstream>
    10. #include <stdio.h>
    11.  
    12.  
    13. //--------------------------------------------------------------
    14. // manifest constants
    15. //--------------------------------------------------------------
    16. #define COMM_BUFFER_SIZE 1024
    17. #define SMALL_BUFFER_SIZE 10
    18.  
    19.  
    20. //--------------------------------------------------------------
    21. // structures
    22. //--------------------------------------------------------------
    23. struct HTTPRequestHeader
    24. {
    25.     char method[SMALL_BUFFER_SIZE];
    26.     char url[MAX_PATH];
    27.     char filepathname[MAX_PATH];
    28.     char httpversion[SMALL_BUFFER_SIZE];
    29.    IN_ADDR client_ip;
    30. };
    31.  
    32. struct ClientInfo
    33. {
    34.     SOCKET client_socket;
    35.     IN_ADDR client_ip;
    36. };
    37.  
    38. struct MimeAssociation
    39. {
    40.     char *file_ext;
    41.     char *mime;
    42. };
    43.  
    44. //--------------------------------------------------------------
    45. // prototypes
    46. //--------------------------------------------------------------
    47. SOCKET StartWebServer();
    48. int WaitForClientConnections(SOCKET server_socket);
    49. void HandleHTTPRequest( void *data );
    50. int findMimeType(const char *extension);
    51. BOOL ParseHTTPHeader(char *receivebuffer, HTTPRequestHeader &requestheader);
    52. void OutputHTTPError(SOCKET client_socket, int statuscode );
    53. void OutputHTTPRedirect(SOCKET client_socket, const char *defaulturl);
    54. void OutputScreenError(const char *errmsg);
    55. int SocketRead(SOCKET client_socket, char *receivebuffer, int buffersize);
    56. void DetermineHost( char *hostname );
    57.  
    58.  
    59. //--------------------------------------------------------------
    60. // global vars
    61. //--------------------------------------------------------------
    62. char wwwroot[MAX_PATH];
    63. char hostname[MAX_PATH];
    64. CRITICAL_SECTION output_criticalsection;
    65.  
    66.  
    67. MimeAssociation mimetypes[] = {
    68.     { ".txt", "text/plain" },
    69.     { ".html","text/html" },
    70.     { ".htm", "text/html" },
    71.     { ".gif", "image/gif" },
    72.     { ".jpg", "image/jpeg" }
    73. };
    74.  
    75.  
    76. //--------------------------------------------------------------
    77. //  main()
    78. //      Start of application.  Initializes winsock and starts
    79. //      server
    80. //--------------------------------------------------------------
    81. int main(int argc, char *argv[])
    82. {
    83.     WSADATA wd;
    84.     SOCKET server_socket;
    85.  
    86.  
    87.     // webserver root directory passed on command-line
    88.     if ( argc == 1 )
    89.     {
    90.         printf("charlotte <wwwroot directory>\r\n");
    91.         printf("ex: charlotte c:\\wwwroot\r\n");
    92.  
    93.         return(1);
    94.     }
    95.  
    96.     // remember the root dir of the webserver
    97.     strcpy(wwwroot,argv[1]);
    98.     printf("wwwroot: %s\r\n",wwwroot);
    99.  
    100.     // init the winsock libraries
    101.     if ( WSAStartup(MAKEWORD(1,1), &wd) != 0 )
    102.     {
    103.         printf("Unable to initialize WinSock 1.1\r\n");
    104.         return(1);
    105.     }
    106.  
    107.     // get name of webserver machine. needed for redirects
    108.    // gethostname does not return a fully qualified host name
    109.     DetermineHost(hostname);
    110.  
    111.  
    112.     // create a critical section for mutual-exclusion synchronization on cout
    113.     InitializeCriticalSection (&output_criticalsection);
    114.  
    115.     // init the webserver
    116.     server_socket = StartWebServer();
    117.     if ( server_socket )
    118.     {
    119.       WaitForClientConnections(server_socket);
    120.         closesocket(server_socket);
    121.     }
    122.     else
    123.         printf("Error in StartWebServer()\r\n");
    124.  
    125.  
    126.     // delete and release resources for critical section
    127.     DeleteCriticalSection (&output_criticalsection);
    128.  
    129.     WSACleanup();
    130.  
    131.     return(0);
    132. }
    133.  
    134. //--------------------------------------------------------------
    135. // WaitForClientConnections()
    136. //      Loops forever waiting for client connections. On connection
    137. //      starts a thread to handling the http transaction
    138. //--------------------------------------------------------------
    139. int WaitForClientConnections(SOCKET server_socket)
    140. {
    141.     SOCKET client_socket;
    142.     SOCKADDR_IN client_address;
    143.     int client_address_len;
    144.     ClientInfo *ci;
    145.  
    146.     client_address_len = sizeof(SOCKADDR_IN);
    147.  
    148.     if ( listen(server_socket,SOMAXCONN) == SOCKET_ERROR )
    149.     {
    150.         OutputScreenError("Error in listen()");
    151.         closesocket(server_socket);
    152.         return(0);
    153.     }
    154.  
    155.    // loop forever accepting client connections. user ctrl-c to exit!
    156.    for ( ;; )
    157.     {
    158.         client_socket = accept(server_socket,(struct sockaddr *)&client_address,&client_address_len);
    159.         if ( client_socket == INVALID_SOCKET )
    160.         {
    161.             OutputScreenError("Error in accept()");
    162.             closesocket(server_socket);
    163.             return(0);
    164.         }
    165.  
    166.       // copy client ip and socket so the HandleHTTPRequest thread
    167.       // and process the request.
    168.         ci = new ClientInfo;
    169.         ci->client_socket = client_socket;
    170.         memcpy(&(ci->client_ip),&client_address.sin_addr.s_addr,4);
    171.  
    172.         // for each request start a new thread!
    173.         _beginthread(HandleHTTPRequest,0,(void *)ci);
    174.     }
    175.  
    176. }
    177.  
    178.  
    179. //--------------------------------------------------------------
    180. //  HandleHTTPRequest()
    181. //      Executed in its own thread to handling http transaction
    182. //--------------------------------------------------------------
    183. void HandleHTTPRequest( void *data )
    184. {
    185.     SOCKET client_socket;
    186.     HTTPRequestHeader requestheader;
    187.     int size;
    188.     char receivebuffer[COMM_BUFFER_SIZE];
    189.     char sendbuffer[COMM_BUFFER_SIZE];
    190.  
    191.     client_socket = ((ClientInfo *)data)->client_socket;
    192.     requestheader.client_ip = ((ClientInfo *)data)->client_ip;
    193.    
    194.     delete data;
    195.  
    196.     size = SocketRead(client_socket,receivebuffer,COMM_BUFFER_SIZE);
    197.     if ( size == SOCKET_ERROR || size == 0 )
    198.     {
    199.         OutputScreenError("Error calling recv()");
    200.         closesocket(client_socket);
    201.         return;
    202.     }
    203.     receivebuffer[size] = NULL;
    204.  
    205.     if ( !ParseHTTPHeader(receivebuffer,requestheader) )
    206.     {
    207.         // handle bad header!
    208.         OutputHTTPError(client_socket, 400);   // 400 - bad request
    209.         return;
    210.     }
    211.  
    212.     if ( strstr(requestheader.method,"GET") )
    213.     {
    214.         if ( strnicmp(requestheader.filepathname,wwwroot,strlen(wwwroot)) == 0 )  // else security violation!
    215.         {
    216.             FILE *in;
    217.             char *filebuffer;
    218.             long filesize;
    219.             DWORD fileattrib;
    220.  
    221.             fileattrib = GetFileAttributes(requestheader.filepathname);
    222.  
    223.             if ( fileattrib != -1 && fileattrib & FILE_ATTRIBUTE_DIRECTORY )
    224.             {
    225.                 OutputHTTPRedirect(client_socket, requestheader.url);
    226.                 return;
    227.             }
    228.  
    229.             in = fopen(requestheader.filepathname,"rb");  // read binary
    230.             if ( !in )
    231.             {
    232.                 // file error, not found?
    233.                 OutputHTTPError(client_socket, 404);   // 404 - not found
    234.                 return;
    235.             }
    236.  
    237.             // determine file size
    238.             fseek(in,0,SEEK_END);
    239.             filesize = ftell(in);
    240.             fseek(in,0,SEEK_SET);
    241.  
    242.             // allocate buffer and read in file contents
    243.             filebuffer = new char[filesize];
    244.             fread(filebuffer,sizeof(char),filesize,in);
    245.             fclose(in);
    246.  
    247.             // send the http header and the file contents to the browser
    248.             strcpy(sendbuffer,"HTTP/1.0 200 OK\r\n");
    249.             strncat(sendbuffer,"Content-Type: ",COMM_BUFFER_SIZE);
    250.             strncat(sendbuffer,mimetypes[findMimeType(requestheader.filepathname)].mime,COMM_BUFFER_SIZE);
    251.             sprintf(sendbuffer+strlen(sendbuffer),"\r\nContent-Length: %ld\r\n",filesize);
    252.             strncat(sendbuffer,"\r\n",COMM_BUFFER_SIZE);
    253.  
    254.             send(client_socket,sendbuffer,strlen(sendbuffer),0);
    255.             send(client_socket,filebuffer,filesize,0);
    256.  
    257.             // log line
    258.             EnterCriticalSection (&output_criticalsection);
    259.          printf("%s%s%s%s%s\r\n",inet_ntoa(requestheader.client_ip)," - ",requestheader.method," ",requestheader.url);
    260.             LeaveCriticalSection (&output_criticalsection);
    261.  
    262.             delete [] filebuffer;
    263.         }
    264.         else
    265.         {
    266.             OutputHTTPError(client_socket, 403);    // 403 - forbidden
    267.             return;
    268.         }
    269.     }
    270.     else
    271.     {
    272.         OutputHTTPError(client_socket, 501);   // 501 not implemented
    273.         return;
    274.     }
    275.  
    276.     closesocket(client_socket);
    277. }
    278.  
    279.  
    280. //--------------------------------------------------------------
    281. //  SocketRead()
    282. //      Reads data from the client socket until it gets a valid http
    283. //      header or the client disconnects.
    284. //--------------------------------------------------------------
    285. int SocketRead(SOCKET client_socket, char *receivebuffer, int buffersize)
    286. {
    287.     int size = 0, totalsize = 0;
    288.  
    289.     do
    290.     {
    291.         size = recv(client_socket,receivebuffer+totalsize,buffersize-totalsize,0);
    292.         if ( size != 0 && size != SOCKET_ERROR )
    293.         {
    294.             totalsize += size;
    295.  
    296.             // are we done reading the http header?
    297.             if ( strstr(receivebuffer,"\r\n\r\n") )
    298.                 break;
    299.         }
    300.         else
    301.             totalsize = size;           // remember error state for return
    302.        
    303.     } while ( size != 0 && size != SOCKET_ERROR );
    304.  
    305.     return(totalsize);
    306. }
    307.  
    308.  
    309. //--------------------------------------------------------------
    310. //  OutputScreenError()
    311. //      Writes an error message to the screen displays the socket
    312. //      error code, clearing the error before exiting.
    313. //--------------------------------------------------------------
    314. void OutputScreenError(const char *errmsg)
    315. {
    316.     EnterCriticalSection (&output_criticalsection);
    317.    printf("%s,%s,%d\r\n",errmsg," - ",WSAGetLastError());
    318.    WSASetLastError(0);
    319.     LeaveCriticalSection (&output_criticalsection);
    320. }
    321.  
    322.  
    323. //--------------------------------------------------------------
    324. //  OutputHTTPError()
    325. //      Sends an http header and html body to the client with
    326. //      error information.
    327. //--------------------------------------------------------------
    328. void OutputHTTPError(SOCKET client_socket, int statuscode)
    329. {
    330.     char headerbuffer[COMM_BUFFER_SIZE];
    331.     char htmlbuffer[COMM_BUFFER_SIZE];
    332.  
    333.     sprintf(htmlbuffer,"<html><body><h2>Error: %d</h2></body></html>",statuscode);
    334.     sprintf(headerbuffer,"HTTP/1.0 %d\r\nContent-Type: text/html\r\nContent-Length: %ld\r\n\r\n",statuscode,strlen(htmlbuffer));
    335.    
    336.     send(client_socket,headerbuffer,strlen(headerbuffer),0);
    337.     send(client_socket,htmlbuffer,strlen(htmlbuffer),0);
    338.  
    339.     closesocket(client_socket);
    340. }
    341.  
    342.  
    343. //--------------------------------------------------------------
    344. //  OutputHTTPRedirect()
    345. //      Writes an HTTP redirect header and body to the client.
    346. //      Called if the user requests a directory causing the redirect
    347. //      to directory/index.html
    348. //--------------------------------------------------------------
    349. void OutputHTTPRedirect(SOCKET client_socket, const char *defaulturl)
    350. {
    351.     char headerbuffer[COMM_BUFFER_SIZE];
    352.     char htmlbuffer[COMM_BUFFER_SIZE];
    353.     char hosturl[MAX_PATH];
    354.  
    355.     sprintf(hosturl,"http://%s",hostname);
    356.     strncat(hosturl,defaulturl,COMM_BUFFER_SIZE);
    357.  
    358.     if ( hosturl[strlen(hosturl)-1] != '/' )
    359.         strncat(hosturl,"/",MAX_PATH);                                     
    360.     strncat(hosturl,"index.html",MAX_PATH);
    361.  
    362.     sprintf(htmlbuffer,"<html><body><a href=\"%s\">%s</a></body></html>",hosturl,hosturl);
    363.     sprintf(headerbuffer,"HTTP/1.0 301\r\nContent-Type: text/html\r\nContent-Length: %ld\r\nLocation: %s\r\n\r\n",strlen(htmlbuffer),hosturl);
    364.    
    365.     send(client_socket,headerbuffer,strlen(headerbuffer),0);
    366.     send(client_socket,htmlbuffer,strlen(htmlbuffer),0);
    367.  
    368.     closesocket(client_socket);
    369. }
    370.  
    371. //--------------------------------------------------------------
    372. //  ParseHTTPHeader()
    373. //      Fills a HTTPRequestHeader with method, url, http version
    374. //      and file system path information.
    375. //--------------------------------------------------------------
    376. BOOL ParseHTTPHeader(char *receivebuffer, HTTPRequestHeader &requestheader)
    377. {
    378.     char *pos;
    379.     // http request header format
    380.     // method uri httpversion
    381.  
    382.     //debugging
    383.     EnterCriticalSection (&output_criticalsection);
    384.    printf("%s\r\n",receivebuffer);
    385.     LeaveCriticalSection (&output_criticalsection);
    386.     // end debuggine   
    387.  
    388.  
    389.  
    390.     pos = strtok(receivebuffer," ");
    391.     if ( pos == NULL )
    392.         return(FALSE);
    393.     strncpy(requestheader.method,pos,SMALL_BUFFER_SIZE);
    394.    
    395.     pos = strtok(NULL," ");
    396.     if ( pos == NULL )
    397.         return(FALSE);
    398.     strncpy(requestheader.url,pos,MAX_PATH);
    399.  
    400.     pos = strtok(NULL,"\r");
    401.     if ( pos == NULL )
    402.         return(FALSE);
    403.     strncpy(requestheader.httpversion,pos,SMALL_BUFFER_SIZE);
    404.  
    405.     // based on the url lets figure out the filename + path
    406.     strncpy(requestheader.filepathname,wwwroot,MAX_PATH);
    407.     strncat(requestheader.filepathname,requestheader.url,MAX_PATH);
    408.  
    409.     // because the filepathname can have relative references  ../ ./
    410.     // call _fullpath to get the absolute 'real' filepath
    411.     // _fullpath seems to handle '/' and '\'
    412.    _fullpath(requestheader.filepathname,requestheader.filepathname,MAX_PATH);
    413.  
    414.     return(TRUE);
    415. }
    416.  
    417.  
    418. //--------------------------------------------------------------
    419. //  StartWebServer()
    420. //      Creates server sock and binds to ip address and port
    421. //--------------------------------------------------------------
    422. SOCKET StartWebServer()
    423. {
    424.     SOCKET s;
    425.  
    426.     s = socket(AF_INET,SOCK_STREAM,0);
    427.     if ( s == INVALID_SOCKET )
    428.     {
    429.         OutputScreenError("Error creating sock()");
    430.         return(0);
    431.     }
    432.    
    433.     SOCKADDR_IN si;
    434.  
    435.     si.sin_family = AF_INET;
    436.     si.sin_port = htons(8080);      // port
    437.     si.sin_addr.s_addr = htonl(INADDR_ANY);
    438.  
    439.     if ( bind(s,(struct sockaddr *) &si,sizeof(SOCKADDR_IN)) == SOCKET_ERROR )
    440.     {
    441.         OutputScreenError("Error in bind()");
    442.         closesocket(s);
    443.         return(0);
    444.     }
    445.  
    446.     return(s);
    447. }
    448.  
    449. //--------------------------------------------------------------
    450. //  findMimeType()
    451. //      Performs linear search through mimetypes array looking for
    452. //      matching file extension returning index of mime type
    453. //--------------------------------------------------------------
    454. int findMimeType(const char *filename)
    455. {
    456.     char *pos;
    457.     int numofelements;
    458.    
    459.     pos = (char*)strrchr(filename,'.');
    460.  
    461.     if ( pos )
    462.     {
    463.         numofelements = sizeof(mimetypes) / sizeof(MimeAssociation);
    464.  
    465.         for ( int x = 0; x < numofelements; ++x )
    466.         {
    467.             if ( stricmp(mimetypes[x].file_ext,pos) == 0 )
    468.                 return(x);
    469.         }
    470.     }
    471.  
    472.     return(0);  // return default mimetype  'text/plain'
    473. }
    474.  
    475. //--------------------------------------------------------------
    476. //  DetermineHost()
    477. //      If webserver needs to redirect user from directory to
    478. //      default html file the server builds a full url and hence
    479. //      needs it's full domain name for http address.
    480. //          http://mymachine.rollins.brevard.edu/index.html
    481. //--------------------------------------------------------------
    482. void DetermineHost( char *hostname )
    483. {
    484.     IN_ADDR in;
    485.    hostent *h;
    486.  
    487.    gethostname(hostname,MAX_PATH);
    488.    h = gethostbyname(hostname);
    489.     memcpy(&in,h->h_addr,4);
    490.     h = gethostbyaddr((char *)&in,4,PF_INET);
    491.     strcpy(hostname,h->h_name);
    492. }
     
  3. skyproc

    skyproc New Member

    Публикаций:
    0
    Регистрация:
    4 май 2007
    Сообщения:
    217
    Большое пасиба Folk Acid!!!
     
  4. skyproc

    skyproc New Member

    Публикаций:
    0
    Регистрация:
    4 май 2007
    Сообщения:
    217
    Нашел полный перевод!!!
    http://book.itep.ru/4/45/http4561.htm#16.7.1.1
     
  5. s0larian

    s0larian New Member

    Публикаций:
    0
    Регистрация:
    15 июл 2004
    Сообщения:
    489
    Адрес:
    Крыжёпполь
    skyproc, эта, HTTP кода на sf.net просто немеряно.

    (для jaja: На любых языках кроме асма)
     
  6. skyproc

    skyproc New Member

    Публикаций:
    0
    Регистрация:
    4 май 2007
    Сообщения:
    217
    На любых языках кроме асма
    ХМ круто но этот форум находитмя как ни как на wasm.ru

    Да и нет таких языков на которых мона обойти хорошо написанный и оптимизированный asm код!!!

    Странно ну если есть ещё такие интузиасты как я то оставляйте координаты, пообщаемси...
     
  7. wasm_test

    wasm_test wasm test user

    Публикаций:
    0
    Регистрация:
    24 ноя 2006
    Сообщения:
    5.582
    Давайте обойдемся без таких заявлений, ибо холивары щас пойдут, что совсем не входит в тематику данного раздела
     
  8. skyproc

    skyproc New Member

    Публикаций:
    0
    Регистрация:
    4 май 2007
    Сообщения:
    217
  9. skyproc

    skyproc New Member

    Публикаций:
    0
    Регистрация:
    4 май 2007
    Сообщения:
    217
    Ещё вопрос...
    Как я говрил приложение мультитредное и выполняется на двухядерном атлоне
    дано два треда в одном адресном пространстве и в какой то момент времени они используют одну и туже функцию в мною написанной DLL.

    Не будет ли конфликтов???
     
  10. Ustus

    Ustus New Member

    Публикаций:
    0
    Регистрация:
    8 авг 2005
    Сообщения:
    834
    Адрес:
    Харьков
    skyproc
    Ну... понаставь критических секций, если есть сомнения...
     
  11. Dukales

    Dukales New Member

    Публикаций:
    0
    Регистрация:
    5 июл 2009
    Сообщения:
    199
     
  12. Dukales

    Dukales New Member

    Публикаций:
    0
    Регистрация:
    5 июл 2009
    Сообщения:
    199
    полное непонимание того, как "это всё дело" происходит в многозадачных операционках
     
  13. Dukales

    Dukales New Member

    Публикаций:
    0
    Регистрация:
    5 июл 2009
    Сообщения:
    199
    если нет самомодификации кода и static и глобальных переменных, от которых что-то критически зависит, то конечно не будет
     
  14. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    Нету никаких причин писать подобное на ассемблере. Да и нету сферического ассемблера в вакууме. ТС пишет на том что знает и этим определяется его выбор. Энтузиасты. ^)
     
  15. s0larian

    s0larian New Member

    Публикаций:
    0
    Регистрация:
    15 июл 2004
    Сообщения:
    489
    Адрес:
    Крыжёпполь
    Умник.. интузиасты есть писать на асме всё. А нормальная практика компилить один и тот же код под несколько процев и операционок.