hermes

HTTP GET/HEAD-only web server for static content.
git clone git://git.francescosaccone.com/hermes
Log | Files | Refs | README | LICENSE

http.c (2676B)


      1 #include "http.h"
      2 
      3 #include <stdio.h>
      4 #include <stdlib.h>
      5 #include <string.h>
      6 
      7 struct http_request *
      8 parse_http_request(char *request) {
      9 	struct http_request *result = malloc(sizeof(struct http_request));
     10 	
     11 	if (result == NULL) {
     12 		return NULL;
     13 	}
     14 
     15 	char *method_string = strtok(request, " "),
     16 	     *path_string = strtok(NULL, " ");
     17 
     18 	if (method_string != NULL) {
     19 		if (strcmp(method_string, "GET") == 0) {
     20 			result->method = GET;
     21 		} else if (strcmp(method_string, "HEAD") == 0) {
     22 			result->method = HEAD;
     23 		} else {
     24 			result->method = UNSUPPORTED;
     25 		}
     26 	}
     27 
     28 	if (path_string != NULL) {
     29 		strncpy(result->path,
     30 		        path_string,
     31 		        HTTP_REQUEST_PATH_MAX_LENGTH - 1);
     32 		result->path[HTTP_REQUEST_PATH_MAX_LENGTH - 1] = '\0';
     33 	}
     34 
     35 	return result;
     36 }
     37 
     38 unsigned int
     39 get_length_of_integer(unsigned int integer) {
     40 	unsigned int result = 0;
     41 
     42 	while (integer > 1) {
     43 		integer /= 10;
     44 		result++;
     45 	}
     46 
     47 	return result;
     48 }
     49 
     50 char *
     51 compose_http_response_head(struct http_response response) {
     52 	size_t size;
     53 	unsigned int status_code = status_map[response.status].code;
     54 	const char *template = "HTTP/1.1 %u %s\r\n"
     55 	                       "Content-Type: %s; charset=UTF-8\r\n"
     56 	                       "Content-Length: %u\r\n",
     57 	           *status_message = status_map[response.status].message,
     58 	           *content_type = response.content_type,
     59 	           *body = response.body;
     60 	char *buffer;
     61 
     62 	/*
     63 	 * This is actually a bit inelegant: it adds the length of 'template'
     64 	 * with the length of each component of http_response; it will result
     65 	 * in something bigger than the actual size of the response due to 
     66 	 * the template patterns in %, but that is just a few bytes and nobody
     67 	 * really minds it.
     68 	 */
     69 	size = strlen(template)
     70 	       + get_length_of_integer(status_code)
     71 	       + strlen(status_message)
     72 	       + strlen(content_type)
     73 	       + get_length_of_integer(strlen(body));
     74 
     75 	buffer = malloc(size);
     76 
     77 	snprintf(buffer, size, template,
     78 	         status_code,
     79 	         status_message,
     80 	         content_type,
     81 	         strlen(body));
     82 
     83 	buffer[size] = '\0';
     84 
     85 	return buffer;
     86 }
     87 
     88 char *
     89 compose_http_response_full(struct http_response response) {
     90 	size_t size;
     91 	const char *template = "%s"
     92 	                       "\r\n"
     93 	                       "%s\n",
     94 	           *head = compose_http_response_head(response),
     95 	           *body = response.body;
     96 	char *buffer;
     97 
     98 	/*
     99 	 * Read the comment inside the compose_http_response_head function in
    100 	 * this same file.
    101 	 */
    102 	size = strlen(template)
    103 	       + strlen(head)
    104 	       + strlen(body);
    105 
    106 	buffer = malloc(size);
    107 
    108 	snprintf(buffer, size, template,
    109 	         head,
    110 	         body);
    111 
    112 	buffer[size] = '\0';
    113 
    114 	return buffer;
    115 }