https://blog.abhijeetr.com/2010/04/very-simple-http-server-writen-in-c.html

    1. /*
    2. AUTHOR: Abhijeet Rastogi (http://www.google.com/profiles/abhijeet.1989)
    3. This is a very simple HTTP server. Default port is 10000 and ROOT for the server is your current working directory..
    4. You can provide command line arguments like:- $./a.aout -p [port] -r [path]
    5. for ex.
    6. $./a.out -p 50000 -r /home/
    7. to start a server at port 50000 with root directory as "/home"
    8. $./a.out -r /home/shadyabhi
    9. starts the server at port 10000 with ROOT as /home/shadyabhi
    10. */
    11. #include<stdio.h>
    12. #include<string.h>
    13. #include<stdlib.h>
    14. #include<unistd.h>
    15. #include<sys/types.h>
    16. #include<sys/stat.h>
    17. #include<sys/socket.h>
    18. #include<arpa/inet.h>
    19. #include<netdb.h>
    20. #include<signal.h>
    21. #include<fcntl.h>
    22. #define CONNMAX 1000
    23. #define BYTES 1024
    24. char *ROOT;
    25. int listenfd, clients[CONNMAX];
    26. void error(char *);
    27. void startServer(char *);
    28. void respond(int);
    29. int main(int argc, char* argv[])
    30. {
    31. struct sockaddr_in clientaddr;
    32. socklen_t addrlen;
    33. char c;
    34. //Default Values PATH = ~/ and PORT=10000
    35. char PORT[6];
    36. ROOT = getenv("PWD");
    37. strcpy(PORT,"10000");
    38. int slot=0;
    39. //Parsing the command line arguments
    40. while ((c = getopt (argc, argv, "p:r:")) != -1)
    41. switch (c)
    42. {
    43. case 'r':
    44. ROOT = malloc(strlen(optarg));
    45. strcpy(ROOT,optarg);
    46. break;
    47. case 'p':
    48. strcpy(PORT,optarg);
    49. break;
    50. case '?':
    51. fprintf(stderr,"Wrong arguments given!!!\n");
    52. exit(1);
    53. default:
    54. exit(1);
    55. }
    56. printf("Server started at port no. %s%s%s with root directory as %s%s%s\n","\033[92m",PORT,"\033[0m","\033[92m",ROOT,"\033[0m");
    57. // Setting all elements to -1: signifies there is no client connected
    58. int i;
    59. for (i=0; i<CONNMAX; i++)
    60. clients[i]=-1;
    61. startServer(PORT);
    62. // ACCEPT connections
    63. while (1)
    64. {
    65. addrlen = sizeof(clientaddr);
    66. clients[slot] = accept (listenfd, (struct sockaddr *) &clientaddr, &addrlen);
    67. if (clients[slot]<0)
    68. error ("accept() error");
    69. else
    70. {
    71. if ( fork()==0 )
    72. {
    73. respond(slot);
    74. exit(0);
    75. }
    76. }
    77. while (clients[slot]!=-1) slot = (slot+1)%CONNMAX;
    78. }
    79. return 0;
    80. }
    81. //start server
    82. void startServer(char *port)
    83. {
    84. struct addrinfo hints, *res, *p;
    85. // getaddrinfo for host
    86. memset (&hints, 0, sizeof(hints));
    87. hints.ai_family = AF_INET;
    88. hints.ai_socktype = SOCK_STREAM;
    89. hints.ai_flags = AI_PASSIVE;
    90. if (getaddrinfo( NULL, port, &hints, &res) != 0)
    91. {
    92. perror ("getaddrinfo() error");
    93. exit(1);
    94. }
    95. // socket and bind
    96. for (p = res; p!=NULL; p=p->ai_next)
    97. {
    98. listenfd = socket (p->ai_family, p->ai_socktype, 0);
    99. if (listenfd == -1) continue;
    100. if (bind(listenfd, p->ai_addr, p->ai_addrlen) == 0) break;
    101. }
    102. if (p==NULL)
    103. {
    104. perror ("socket() or bind()");
    105. exit(1);
    106. }
    107. freeaddrinfo(res);
    108. // listen for incoming connections
    109. if ( listen (listenfd, 1000000) != 0 )
    110. {
    111. perror("listen() error");
    112. exit(1);
    113. }
    114. }
    115. //client connection
    116. void respond(int n)
    117. {
    118. char mesg[99999], *reqline[3], data_to_send[BYTES], path[99999];
    119. int rcvd, fd, bytes_read;
    120. memset( (void*)mesg, (int)'\0', 99999 );
    121. rcvd=recv(clients[n], mesg, 99999, 0);
    122. if (rcvd<0) // receive error
    123. fprintf(stderr,("recv() error\n"));
    124. else if (rcvd==0) // receive socket closed
    125. fprintf(stderr,"Client disconnected upexpectedly.\n");
    126. else // message received
    127. {
    128. printf("%s", mesg);
    129. reqline[0] = strtok (mesg, " \t\n");
    130. if ( strncmp(reqline[0], "GET\0", 4)==0 )
    131. {
    132. reqline[1] = strtok (NULL, " \t");
    133. reqline[2] = strtok (NULL, " \t\n");
    134. if ( strncmp( reqline[2], "HTTP/1.0", 8)!=0 && strncmp( reqline[2], "HTTP/1.1", 8)!=0 )
    135. {
    136. write(clients[n], "HTTP/1.0 400 Bad Request\n", 25);
    137. }
    138. else
    139. {
    140. if ( strncmp(reqline[1], "/\0", 2)==0 )
    141. reqline[1] = "/index.html"; //Because if no file is specified, index.html will be opened by default (like it happens in APACHE...
    142. strcpy(path, ROOT);
    143. strcpy(&path[strlen(ROOT)], reqline[1]);
    144. printf("file: %s\n", path);
    145. if ( (fd=open(path, O_RDONLY))!=-1 ) //FILE FOUND
    146. {
    147. send(clients[n], "HTTP/1.0 200 OK\n\n", 17, 0);
    148. while ( (bytes_read=read(fd, data_to_send, BYTES))>0 )
    149. write (clients[n], data_to_send, bytes_read);
    150. }
    151. else write(clients[n], "HTTP/1.0 404 Not Found\n", 23); //FILE NOT FOUND
    152. }
    153. }
    154. }
    155. //Closing SOCKET
    156. shutdown (clients[n], SHUT_RDWR); //All further send and recieve operations are DISABLED...
    157. close(clients[n]);
    158. clients[n]=-1;
    159. }
    1. $ gcc httpserver.c
    2. $ ./a.out -p 50000
    3. Server started at port no. 50000 with root directory as /home/XXX/concurrency

    http://127.0.0.1:50000/

    1. $ ./a.out -p 50000
    2. Server started at port no. 50000 with root directory as /home/ningluwsl/concurrency
    3. GET / HTTP/1.1
    4. Host: 127.0.0.1:50000
    5. Connection: keep-alive
    6. Cache-Control: max-age=0
    7. sec-ch-ua: " Not A;Brand";v="99", "Chromium";v="102", "Microsoft Edge";v="102"
    8. sec-ch-ua-mobile: ?0
    9. sec-ch-ua-platform: "Windows"
    10. Upgrade-Insecure-Requests: 1
    11. User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.5005.63 Safari/537.36 Edg/102.0.1245.30
    12. Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
    13. Sec-Fetch-Site: none
    14. Sec-Fetch-Mode: navigate
    15. Sec-Fetch-User: ?1
    16. Sec-Fetch-Dest: document
    17. Accept-Encoding: gzip, deflate, br
    18. Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
    19. file: /home/XXX/concurrency/index.html