|
|
/*
* Copyright (c) 2011 and 2012, Dustin Lundquist <dustin@null-ptr.net> * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#include <stdlib.h> /* malloc() */
#include <string.h> /* strncpy() */
#include <strings.h> /* strncasecmp() */
#include <ctype.h> /* isblank() */
#include "http.h"
#include "protocol.h"
#define SERVER_NAME_LEN 256
static int parse_http_header(const char *, size_t, char **); static int get_header(const char *, const char *, int, char **); static int next_header(const char **, int *);
static const protocol_t http_protocol_st = { .default_port = 80, .parse_packet = &parse_http_header, }; const protocol_t *const http_protocol = &http_protocol_st;
/*
* Parses a HTTP request for the Host: header * * Returns: * >=0 - length of the hostname and updates *hostname * caller is responsible for freeing *hostname * -1 - Incomplete request * -2 - No Host header included in this request * -3 - Invalid hostname pointer * -4 - malloc failure * < -4 - Invalid HTTP request * */ static int parse_http_header(const char *data, size_t data_len, char **hostname) { int result, i;
if (hostname == NULL) return -3;
if (data_len == 0) return -1;
result = get_header("Host:", data, data_len, hostname); if (result < 0) return result;
/*
* if the user specifies the port in the request, it is included here. * Host: example.com:80 * so we trim off port portion */ for (i = result - 1; i >= 0; i--) if ((*hostname)[i] == ':') { (*hostname)[i] = '\0'; result = i; break; }
return result; }
static int get_header(const char *header, const char *data, int data_len, char **value) { int len, header_len;
header_len = strlen(header);
/* loop through headers stopping at first blank line */ while ((len = next_header(&data, &data_len)) != 0) if (len > header_len && strncasecmp(header, data, header_len) == 0) { /* Eat leading whitespace */ while (header_len < len && isblank((unsigned char)data[header_len])) header_len++;
*value = malloc(len - header_len + 1); if (*value == NULL) return -4;
strncpy(*value, data + header_len, len - header_len); (*value)[len - header_len] = '\0';
return len - header_len; }
/* If there is no data left after reading all the headers then we do not
* have a complete HTTP request, there must be a blank line */ if (data_len == 0) return -1;
return -2; }
static int next_header(const char **data, int *len) { int header_len;
/* perhaps we can optimize this to reuse the value of header_len, rather
* than scanning twice. * Walk our data stream until the end of the header */ while (*len > 2 && (*data)[0] != '\r' && (*data)[1] != '\n') { (*len)--; (*data)++; }
/* advanced past the <CR><LF> pair */ *data += 2; *len -= 2;
/* Find the length of the next header */ header_len = 0; while (*len > header_len + 1 && (*data)[header_len] != '\r' && (*data)[header_len + 1] != '\n') header_len++;
return header_len; }
|