HTTP Parser and message builder / objects in plain C Snapshot
Classes | Defines | Typedefs | Functions
http.c File Reference
#include "http.h"
#include <sutils.h>
#include <charclass.h>
#include <stdio.h>

Go to the source code of this file.

Classes

struct  tagHEADER_HASH_ACTION

Defines

#define S_METHOD_GET   "GET"
#define S_METHOD_GET_LEN   3
#define S_METHOD_POST   "POST"
#define S_METHOD_POST_LEN   4
#define S_METHOD_PUT   "PUT"
#define S_METHOD_PUT_LEN   3
#define S_METHOD_DELETE   "DELETE"
#define S_METHOD_DELETE_LEN   6
#define S_METHOD_HEAD   "HEAD"
#define S_METHOD_HEAD_LEN   4
#define S_METHOD_OPTIONS   "OPTIONS"
#define S_METHOD_OPTIONS_LEN   7
#define S_METHOD_TRACE   "TRACE"
#define S_METHOD_TRACE_LEN   5
#define S_METHOD_CONNECT   "CONNECT"
#define S_METHOD_CONNECT_LEN   7
#define HTTP_START_S   "HTTP/1."
#define HTTP_START_S_LEN   7
#define HTTP_EOF_LINE   "\r\n"
#define HTTP_EOF_LINE_LEN   2
#define to_lower(pos)
#define MAX_HTTP_TOKEN_SIZE   120
#define S_CONNECTION_CLOSE   "Connection: close\r\n"
#define S_CONNECTION_CLOSE_LEN   19
#define S_TRANSFER_CHUNKED   "Transfer-encoding: chunked\r\n"
#define S_TRANSFER_CHUNKED_LEN   28
#define RETURN_WRITER_MORE_DATA

Typedefs

typedef struct
tagHEADER_HASH_ACTION 
HEADER_HASH_ACTION

Functions

int init_parsers_request_header (HTTP_PARSER *parser)
int init_parsers_general_header (HTTP_PARSER *parser)
M_INLINE int http_is_ctl (char ch)
M_INLINE int http_is_ctl_or_space (char ch)
M_INLINE int http_is_space (char ch)
M_INLINE int http_is_separator (char ch)
static void free_stringpair (DLISTUNR *list, void *entry, void *context)
int HTTP_MESSAGE_init (HTTP_MESSAGE *message)
void HTTP_MESSAGE_free (HTTP_MESSAGE *message)
int HTTP_MESSAGE_add_header (HTTP_MESSAGE *message, const char *name, const char *value)
const char * HTTP_MESSAGE_find_header (HTTP_MESSAGE *message, const char *name)
STRINGPAIRHTTP_MESSAGE_first_header (HTTP_MESSAGE *message, DLISTUNR_position *pos)
STRINGPAIRHTTP_MESSAGE_next_header (HTTP_MESSAGE *message, DLISTUNR_position *pos)
static int hash_compare (HASH_Entry *entry, void *key, ssize_t key_length)
int HTTP_PARSER_init (HTTP_PARSER *parser)
int HTTP_PARSER_free (HTTP_PARSER *parser)
int HTTP_add_header_parser (HTTP_PARSER *parser, const char *header_name, HEADER_ACTION action_func)
 add a parser for a specific http header type
PARSER_STATUS HTTP_get_line (BF *bf, char **start_line)
 returns next raw line from http header, adjoins line continuations.
int HTTP_get_header_token (HTTP_PARSER *parser)
 return next token while parsing http header value.
PARSER_STATUS HTTP_parse_header_line (HTTP_PARSER *parser, HTTP_MESSAGE *request, BF *bf, int *eof_header)
 dispatch parsing of one http header
int HTTP_PARSER_content_length_init (HTTP_PARSER *parser, HTTP_MESSAGE *msg)
 start parsing content length message body
int HTTP_PARSER_content_length_process (HTTP_PARSER *parser, BF *bf, HTTP_PROCESS_MSG_DATA cb, HTTP_MESSAGE *msg, void *ctx)
 consume content length message body.
int HTTP_PARSER_chunked_data_init (HTTP_PARSER *parser)
 start parsing chunked data
PARSER_STATUS HTTP_PARSER_chunked_data_process (HTTP_PARSER *parser, BF *bf, HTTP_PROCESS_MSG_DATA cb, HTTP_MESSAGE *msg, void *ctx)
 finish parsind chunked content data.
static PARSER_STATUS parse_request_line (HTTP_REQUEST *request, BF *bf)
int HTTP_REQUEST_PARSER_init (HTTP_REQUEST_PARSER *parser, HTTP_REQ_HEADER_PARSED header_parsed, HTTP_REQ_MESSAGE_BODY_DATA on_message_body_data, HTTP_REQ_FINISHED on_request_finished, void *ctx)
 initialise request parser object
PARSER_STATUS HTTP_REQUEST_PARSER_process (HTTP_REQUEST_PARSER *parser, HTTP_REQUEST *request, BF *bf)
 parse a http request
int HTTP_REQUEST_is_persistent (HTTP_REQUEST *message)
static PARSER_STATUS parse_response_line (HTTP_RESPONSE *response, BF *bf)
int HTTP_RESPONSE_PARSER_init (HTTP_RESPONSE_PARSER *parser, HTTP_RESP_HEADER_PARSED header_parsed, HTTP_RESP_MESSAGE_BODY_DATA on_message_body_data, HTTP_RESP_FINISHED on_request_finished, void *ctx)
 initialise request parser object
PARSER_STATUS HTTP_RESPONSE_PARSER_process (HTTP_RESPONSE_PARSER *parser, HTTP_RESPONSE *response, BF *bf)
 parse a http response
static const char * http_version_to_str (Http_version_type ver)
static const char * get_reason_phrase (int code)
PARSER_STATUS HTTP_RESPONSE_WRITER_write (HTTP_RESPONSE_WRITER *writer, BF *bf)

Define Documentation

#define HTTP_EOF_LINE   "\r\n"

Definition at line 31 of file http.c.

#define HTTP_EOF_LINE_LEN   2

Definition at line 32 of file http.c.

#define HTTP_START_S   "HTTP/1."

Definition at line 26 of file http.c.

#define HTTP_START_S_LEN   7

Definition at line 27 of file http.c.

#define MAX_HTTP_TOKEN_SIZE   120

Definition at line 154 of file http.c.

#define RETURN_WRITER_MORE_DATA
Value:
if (bf->start == bf->put_pos) { \
    return PARSER_STATUS_ERROR;  /* the buffer can't hold a single value */ \
  } \
  return PARSER_STATUS_NEED_MORE_DATA;

Definition at line 939 of file http.c.

#define S_CONNECTION_CLOSE   "Connection: close\r\n"

Definition at line 932 of file http.c.

#define S_CONNECTION_CLOSE_LEN   19

Definition at line 933 of file http.c.

#define S_METHOD_CONNECT   "CONNECT"

Definition at line 23 of file http.c.

#define S_METHOD_CONNECT_LEN   7

Definition at line 24 of file http.c.

#define S_METHOD_DELETE   "DELETE"

Definition at line 15 of file http.c.

#define S_METHOD_DELETE_LEN   6

Definition at line 16 of file http.c.

#define S_METHOD_GET   "GET"

Definition at line 9 of file http.c.

#define S_METHOD_GET_LEN   3

Definition at line 10 of file http.c.

#define S_METHOD_HEAD   "HEAD"

Definition at line 17 of file http.c.

#define S_METHOD_HEAD_LEN   4

Definition at line 18 of file http.c.

#define S_METHOD_OPTIONS   "OPTIONS"

Definition at line 19 of file http.c.

#define S_METHOD_OPTIONS_LEN   7

Definition at line 20 of file http.c.

#define S_METHOD_POST   "POST"

Definition at line 11 of file http.c.

#define S_METHOD_POST_LEN   4

Definition at line 12 of file http.c.

#define S_METHOD_PUT   "PUT"

Definition at line 13 of file http.c.

#define S_METHOD_PUT_LEN   3

Definition at line 14 of file http.c.

#define S_METHOD_TRACE   "TRACE"

Definition at line 21 of file http.c.

#define S_METHOD_TRACE_LEN   5

Definition at line 22 of file http.c.

#define S_TRANSFER_CHUNKED   "Transfer-encoding: chunked\r\n"

Definition at line 935 of file http.c.

#define S_TRANSFER_CHUNKED_LEN   28

Definition at line 936 of file http.c.

#define to_lower (   pos)
Value:
if (is_upper_case( *pos )) { \
    *pos = *pos - 'A' + 'a'; \
  }

Definition at line 38 of file http.c.


Typedef Documentation


Function Documentation

static void free_stringpair ( DLISTUNR *  list,
void *  entry,
void *  context 
) [static]

Definition at line 73 of file http.c.

{
  STRINGPAIR *pair = (STRINGPAIR *) entry;
 
  M_UNUSED(list);
  M_UNUSED(context);
 
  free( pair->key );
  free( pair->value );
}
static const char* get_reason_phrase ( int  code) [static]

Definition at line 945 of file http.c.

{
    switch( code ) {
          case 100:         return "Continue";
          case 101:         return "Switching Protocols";
          case 200:         return "OK";
          case 201:         return "Created";
          case 202:         return "Accepted";
          case 203:         return "Non-Authoritative Information";
          case 204:         return "No Content";
          case 205:         return "Reset Content";
          case 206:         return "Partial Content";
          case 300:         return "Multiple Choices";
          case 301:         return "Moved Permanently";
          case 302:         return "Found";
          case 303:         return "See Other";
          case 304:         return "Not Modified";
          case 305:         return "Use Proxy";
          case 307:         return "Temporary Redirect";
          case 400:         return "Bad Request";
          case 401:         return "Unauthorized";
          case 402:         return "Payment Required";
          case 403:         return "Forbidden";
          case 404:         return "Not Found";
          case 405:         return "Method Not Allowed";
          case 406:         return "Not Acceptable";
          case 407:         return "Proxy Authentication Required";
          case 408:         return "Request Time-out";
          case 409:         return "Conflict";
          case 410:         return "Gone";
          case 411:         return "Length Required";
          case 412:         return "Precondition Failed";
          case 413:         return "Request Entity Too Large";
          case 414:         return "Request-URI Too Large";
          case 415:         return "Unsupported Media Type";
          case 416:         return "Requested range not satisfiable";
          case 417:         return "Expectation Failed";
          case 500:         return "Internal Server Error";
          case 501:         return "Not Implemented";
          case 502:         return "Bad Gateway";
          case 503:         return "Service Unavailable";
          case 504:         return "Gateway Time-out";
          case 505:         return "HTTP Version not supported";
   }
   return "";
}
static int hash_compare ( HASH_Entry *  entry,
void *  key,
ssize_t  key_length 
) [static]

Definition at line 156 of file http.c.

{
  HEADER_HASH_ACTION *lhs;

  lhs = (HEADER_HASH_ACTION *) entry;

  return strncmp(lhs->key, key, key_length); 
}
M_INLINE int http_is_ctl ( char  ch)

Definition at line 45 of file http.c.

{
    return (ch >=0 && ch <= 31) || ch == 127;
}
M_INLINE int http_is_ctl_or_space ( char  ch)

Definition at line 50 of file http.c.

{
    return (ch >=0 && ch <= 32) || ch == 127;
}
M_INLINE int http_is_separator ( char  ch)

Definition at line 64 of file http.c.

{
  return ch == '('  || ch ==  ')' || ch ==  '<' || ch ==  '>'  || ch ==  '@'
      || ch ==  ',' || ch ==  ';' || ch ==  ':' || ch ==  '\\' || ch ==  '"'
      || ch ==  '/' || ch ==  '[' || ch ==  ']' || ch ==  '?'  || ch ==  '='
      || ch ==  '{' || ch ==  '}' || ch ==  ' ' || ch ==  '\t';
}
M_INLINE int http_is_space ( char  ch)

Definition at line 55 of file http.c.

{
  return ch == ' ' || ch == '\t';
}
static const char* http_version_to_str ( Http_version_type  ver) [static]

Definition at line 921 of file http.c.

{
  switch(ver) {
    case HTTP_VERSION_1_0:
      return "1.0";
    case HTTP_VERSION_1_1:
      return "1.1";
  }
  return "";
}
int init_parsers_general_header ( HTTP_PARSER parser)

Definition at line 113 of file hparse.c.

{
  if (HTTP_add_header_parser( parser, "content-length",  parser_content_length_header) ||
      HTTP_add_header_parser( parser, "connection",  parser_connection_header) || 
       HTTP_add_header_parser( parser, "transfer-encoding",  parser_transfer_encoding_header) ) {
    return -1;
  }
  return 0;
}
int init_parsers_request_header ( HTTP_PARSER parser)

Definition at line 123 of file hparse.c.

{
  if (HTTP_add_header_parser( parser, "expect",  parser_expect_header) || 
      HTTP_add_header_parser( parser, "host",  parser_host_header) ) {
    return -1;
  }
  return 0;
}
static PARSER_STATUS parse_request_line ( HTTP_REQUEST request,
BF *  bf 
) [static]

Definition at line 544 of file http.c.

{
  Http_method_type method;
  char *eof,*tok, *line;
  PARSER_STATUS rt;  

  rt = HTTP_get_line( bf, &line );
  if (rt != PARSER_STATUS_COMPLETED) {
    return rt;
  }

  switch( *line ) {
    case 'G':
      if (strncmp( line, S_METHOD_GET, S_METHOD_GET_LEN ) != 0) {
        return PARSER_STATUS_ERROR;
      }
      method = HTTP_METHOD_GET; 
      line += S_METHOD_GET_LEN;
      break;
    case 'P':
      if (strncmp( line, S_METHOD_POST, S_METHOD_POST_LEN ) == 0) {
        method = HTTP_METHOD_POST;
        line += S_METHOD_POST_LEN;
      } else if (strncmp( line, S_METHOD_PUT, S_METHOD_PUT_LEN ) == 0) {
        method = HTTP_METHOD_PUT; 
        line += S_METHOD_PUT_LEN;
      } else {
        return PARSER_STATUS_ERROR;
      }
      break;
    case 'H':
      if (strncmp( line, S_METHOD_HEAD, S_METHOD_HEAD_LEN ) != 0) {
        return  PARSER_STATUS_ERROR;
      }
      method = HTTP_METHOD_HEAD;
      line += S_METHOD_HEAD_LEN ;
      break;
    case 'D':
      if (strncmp( line, S_METHOD_DELETE, S_METHOD_DELETE_LEN ) != 0) {
        return  PARSER_STATUS_ERROR;
      }
      method = HTTP_METHOD_DELETE;
      line += S_METHOD_DELETE_LEN ;
      break;
    case 'T':
      if (strncmp( line, S_METHOD_TRACE, S_METHOD_TRACE_LEN ) != 0) {
        return PARSER_STATUS_ERROR;
      }
      method = HTTP_METHOD_TRACE;
      line += S_METHOD_TRACE_LEN ;
      break;
    case 'C':
      if (strncmp( line, S_METHOD_CONNECT, S_METHOD_CONNECT_LEN ) != 0) {
        return PARSER_STATUS_ERROR;
      }
      method = HTTP_METHOD_CONNECT; 
      line += S_METHOD_CONNECT_LEN;
      break;
    default:
      return -1;
  }
  request->method = method;

  tok =  get_token( line, &eof );
  if (!tok) {
   return PARSER_STATUS_ERROR;
  }

  *eof = 0;
  request->raw_url = strdup( tok );

  if (method != HTTP_METHOD_CONNECT) {
    if (URI_parse( &request->url, tok )) {
      return PARSER_STATUS_ERROR;
    }
  } else {
    if (strcmp(tok, "*") != 0) {
      return PARSER_STATUS_ERROR;
    }
    URI_init( &request->url );
  }

  tok =  get_token( eof+1, &eof );
  if (strncmp( tok, HTTP_START_S, HTTP_START_S_LEN ) != 0) {
    return PARSER_STATUS_ERROR;
  }
  tok += HTTP_START_S_LEN;

  switch(tok[0]) {
     case '0':
        request->version = HTTP_VERSION_1_0;
        break;
     case '1':
        request->version =  HTTP_VERSION_1_1; 
        break;
     default:
        return PARSER_STATUS_ERROR;
  }
  return PARSER_STATUS_COMPLETED;
}
static PARSER_STATUS parse_response_line ( HTTP_RESPONSE response,
BF *  bf 
) [static]

Definition at line 779 of file http.c.

{
  PARSER_STATUS rt;  
  char *line, *tok, *eof;
  int st;

  rt = HTTP_get_line( bf, &line );
  if (rt != PARSER_STATUS_COMPLETED) {
    return rt;
  }

  tok = line;
  if (strncmp( tok, HTTP_START_S, HTTP_START_S_LEN ) != 0) {
    return PARSER_STATUS_ERROR;
  }
  tok += HTTP_START_S_LEN;

  switch(tok[0]) {
     case '0':
        response->version = HTTP_VERSION_1_0;
        break;
     case '1':
        response->version =  HTTP_VERSION_1_1; 
        break;
     default:
        return PARSER_STATUS_ERROR;
  }
 
  tok =  get_token( line, &eof );
  if (!tok) {
   return PARSER_STATUS_ERROR;
  }

  st = atoi( tok );
  if (st < 100 || st >= 600) {
    return PARSER_STATUS_ERROR;
  }
 
  response->status_code = st;

  return PARSER_STATUS_COMPLETED;
}