- /*
- * webServer.c
- *
- * Created on: Nov 3, 2012
- * Author: pavithra
- *
- * A web server in C language using only the standard libraries.
- * The port number is passed as an argument.
- *
- */
- #include <stdio.h>
- #include <unistd.h>
- #include <stdlib.h>
- #include <string.h>
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <fcntl.h>
- #include <errno.h>
- #define EOL "\\r\\n"
- #define EOL_SIZE 2
- typedef struct {
- char *ext;
- char *mediatype;
- } extn;
- //Possible media types
- extn extensions[] ={
- {"gif", "image/gif" },
- {"txt", "text/plain" },
- {"jpg", "image/jpg" },
- {"jpeg","image/jpeg"},
- {"png", "image/png" },
- {"ico", "image/ico" },
- {"zip", "image/zip" },
- {"gz", "image/gz" },
- {"tar", "image/tar" },
- {"htm", "text/html" },
- {"html","text/html" },
- {"php", "text/html" },
- {"pdf","application/pdf"},
- {"zip","application/octet-stream"},
- {"rar","application/octet-stream"},
- {0,0} };
- /*
- A helper function
- */
- void error(const char *msg) {
- perror(msg);
- exit(1);
- }
- /*
- A helper function
- */
- int get_file_size(int fd) {
- struct stat stat_struct;
- if (fstat(fd, &stat_struct) == -1)
- return (1);
- return (int) stat_struct.st_size;
- }
- /*
- A helper function
- */
- void send_new(int fd, char *msg) {
- int len = strlen(msg);
- if (send(fd, msg, len, 0) == -1) {
- printf("Error in send\\n");
- }
- }
- /*
- This function recieves the buffer
- until an "End of line(EOL)" byte is recieved
- */
- int recv_new(int fd, char *buffer) {
- char *p = buffer; // Use of a pointer to the buffer rather than dealing with the buffer directly
- int eol_matched = 0; // Use to check whether the recieved byte is matched with the buffer byte or not
- while (recv(fd, p, 1, 0) != 0) // Start receiving 1 byte at a time
- {
- if (*p == EOL[eol_matched]) // if the byte matches with the first eol byte that is '\\r'
- {
- ++eol_matched;
- if (eol_matched == EOL_SIZE) // if both the bytes matches with the EOL
- {
- *(p + 1 - EOL_SIZE) = '\\0'; // End the string
- return (strlen(buffer)); // Return the bytes recieved
- }
- } else {
- eol_matched = 0;
- }
- p++; // Increment the pointer to receive next byte
- }
- return (0);
- }
- /*
- A helper function: Returns the
- web root location.
- */
- char* webroot() {
- // open the file "conf" for reading
- FILE *in = fopen("conf", "rt");
- // read the first line from the file
- char buff[1000];
- fgets(buff, 1000, in);
- // close the stream
- fclose(in);
- char* nl_ptr = strrchr(buff, '\\n');
- if (nl_ptr != NULL)
- *nl_ptr = '\\0';
- return strdup(buff);
- }
- /*
- Handles php requests
- */
- void php_cgi(char* script_path, int fd) {
- send_new(fd, "HTTP/1.1 200 OK\\n Server: Web Server in C\\n Connection: close\\n");
- dup2(fd, STDOUT_FILENO);
- char script[500];
- strcpy(script, "SCRIPT_FILENAME=");
- strcat(script, script_path);
- putenv("GATEWAY_INTERFACE=CGI/1.1");
- putenv(script);
- putenv("QUERY_STRING=");
- putenv("REQUEST_METHOD=GET");
- putenv("REDIRECT_STATUS=true");
- putenv("SERVER_PROTOCOL=HTTP/1.1");
- putenv("REMOTE_HOST=127.0.0.1");
- execl("/usr/bin/php-cgi", "php-cgi", NULL);
- }
- /*
- This function parses the HTTP requests,
- arrange resource locations,
- check for supported media types,
- serves files in a web root,
- sends the HTTP error codes.
- */
- int connection(int fd) {
- char request[500], resource[500], *ptr;
- int fd1, length;
- if (recv_new(fd, request) == 0) {
- printf("Recieve Failed\\n");
- }
- printf("%s\\n", request);
- // Check for a valid browser request
- ptr = strstr(request, " HTTP/");
- if (ptr == NULL) {
- printf("NOT HTTP !\\n");
- } else {
- *ptr = 0;
- ptr = NULL;
- if (strncmp(request, "GET ", 4) == 0) {
- ptr = request + 4;
- }
- if (ptr == NULL) {
- printf("Unknown Request ! \\n");
- } else {
- if (ptr[strlen(ptr) - 1] == '/') {
- strcat(ptr, "index.html");
- }
- strcpy(resource, webroot());
- strcat(resource, ptr);
- char* s = strchr(ptr, '.');
- int i;
- for (i = 0; extensions[i].ext != NULL; i++) {
- if (strcmp(s + 1, extensions[i].ext) == 0) {
- fd1 = open(resource, O_RDONLY, 0);
- printf("Opening \\"%s\\"\\n", resource);
- if (fd1 == -1) {
- printf("404 File not found Error\\n");
- send_new(fd, "HTTP/1.1 404 Not Found\\r\\n");
- send_new(fd, "Server : Web Server in C\\r\\n\\r\\n");
- send_new(fd, "<html><head><title>404 Not Found</head></title>");
- send_new(fd, "<body><p>404 Not Found: The requested resource could not be found!</p></body></html>");
- //Handling php requests
- } else if (strcmp(extensions[i].ext, "php") == 0) {
- php_cgi(resource, fd);
- sleep(1);
- close(fd);
- exit(1);
- } else {
- printf("200 OK, Content-Type: %s\\n\\n",
- extensions[i].mediatype);
- send_new(fd, "HTTP/1.1 200 OK\\r\\n");
- send_new(fd, "Server : Web Server in C\\r\\n\\r\\n");
- if (ptr == request + 4) // if it is a GET request
- {
- if ((length = get_file_size(fd1)) == -1)
- printf("Error in getting size !\\n");
- size_t total_bytes_sent = 0;
- ssize_t bytes_sent;
- while (total_bytes_sent < length) {
- //Zero copy optimization
- if ((bytes_sent = sendfile(fd, fd1, 0,
- length - total_bytes_sent)) <= 0) {
- if (errno == EINTR || errno == EAGAIN) {
- continue;
- }
- perror("sendfile");
- return -1;
- }
- total_bytes_sent += bytes_sent;
- }
- }
- }
- break;
- }
- int size = sizeof(extensions) / sizeof(extensions[0]);
- if (i == size - 2) {
- printf("415 Unsupported Media Type\\n");
- send_new(fd, "HTTP/1.1 415 Unsupported Media Type\\r\\n");
- send_new(fd, "Server : Web Server in C\\r\\n\\r\\n");
- send_new(fd, "<html><head><title>415 Unsupported Media Type</head></title>");
- send_new(fd, "<body><p>415 Unsupported Media Type!</p></body></html>");
- }
- }
- close(fd);
- }
- }
- shutdown(fd, SHUT_RDWR);
- }
- int main(int argc, char *argv[]) {
- int sockfd, newsockfd, portno, pid;
- socklen_t clilen;
- struct sockaddr_in serv_addr, cli_addr;
- if (argc < 2) {
- fprintf(stderr, "ERROR, no port provided\\n");
- exit(1);
- }
- sockfd = socket(AF_INET, SOCK_STREAM, 0);
- if (sockfd < 0)
- error("ERROR opening socket");
- bzero((char *) &serv_addr, sizeof(serv_addr));
- portno = atoi(argv[1]);
- serv_addr.sin_family = AF_INET;
- serv_addr.sin_addr.s_addr = INADDR_ANY;
- serv_addr.sin_port = htons(portno);
- if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
- error("ERROR on binding");
- listen(sockfd, 5);
- clilen = sizeof(cli_addr);
- /*
- Server runs forever, forking off a separate
- process for each connection.
- */
- while (1) {
- newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
- if (newsockfd < 0)
- error("ERROR on accept");
- pid = fork();
- if (pid < 0)
- error("ERROR on fork");
- if (pid == 0) {
- close(sockfd);
- connection(newsockfd);
- exit(0);
- } else
- close(newsockfd);
- } /* end of while */
- close(sockfd);
- return 0; /* we never get here */
- }
- //该片段来自于http://www.codesnippet.cn/detail/311020136820.html
来源: http://www.codesnippet.cn/detail/311020136820.html