test

Fork of mbed-libxively-6eca970 by Xively Official

Committer:
xively
Date:
Wed Jun 26 10:40:43 2013 +0000
Revision:
0:82702e998d3f
libxively v0.1.1-rc0 (34c8b32)

Who changed what in which revision?

UserRevisionLine numberNew contents of line
xively 0:82702e998d3f 1 // Copyright (c) 2003-2013, LogMeIn, Inc. All rights reserved.
xively 0:82702e998d3f 2 // This is part of Xively C library, it is under the BSD 3-Clause license.
xively 0:82702e998d3f 3
xively 0:82702e998d3f 4 /**
xively 0:82702e998d3f 5 * \file http_layer_parser.c
xively 0:82702e998d3f 6 * \author Olgierd Humenczuk
xively 0:82702e998d3f 7 * \brief Our simple HTTP parser [see http_layer_parser.h]
xively 0:82702e998d3f 8 */
xively 0:82702e998d3f 9
xively 0:82702e998d3f 10 #include <stdio.h>
xively 0:82702e998d3f 11 #include <string.h>
xively 0:82702e998d3f 12 #include <stdlib.h>
xively 0:82702e998d3f 13
xively 0:82702e998d3f 14 #include "xively.h"
xively 0:82702e998d3f 15 #include "xi_macros.h"
xively 0:82702e998d3f 16 #include "http_consts.h"
xively 0:82702e998d3f 17 #include "http_layer_parser.h"
xively 0:82702e998d3f 18 #include "xi_debug.h"
xively 0:82702e998d3f 19 #include "xi_err.h"
xively 0:82702e998d3f 20
xively 0:82702e998d3f 21 static const char XI_HTTP_STATUS_PATTERN[] =
xively 0:82702e998d3f 22 "HTTP/%d.%d %d %" XI_STR(XI_HTTP_STATUS_STRING_SIZE) "[^\r\n]\r\n"; //!< the match pattern
xively 0:82702e998d3f 23
xively 0:82702e998d3f 24 #define SET_HTTP_STATUS_PATTERN(a,b,c,d) XI_HTTP_STATUS_PATTERN, &a, &b, &c, d
xively 0:82702e998d3f 25
xively 0:82702e998d3f 26 static const char XI_HTTP_TOKEN_NAMES[ XI_HTTP_HEADERS_COUNT ][ XI_HTTP_HEADER_NAME_MAX_SIZE ] =
xively 0:82702e998d3f 27 {
xively 0:82702e998d3f 28 "date" // XI_HTTP_HEADER_DATE
xively 0:82702e998d3f 29 , "content-type" // XI_HTTP_HEADER_CONTENT_TYPE
xively 0:82702e998d3f 30 , "content-length" // XI_HTTP_HEADER_CONTENT_LENGTH
xively 0:82702e998d3f 31 , "connection" // XI_HTTP_HEADER_CONNECTION
xively 0:82702e998d3f 32 , "x-request-id" // XI_HTTP_HEADER_X_REQUEST_ID
xively 0:82702e998d3f 33 , "cache-control" // XI_HTTP_HEADER_CACHE_CONTROL
xively 0:82702e998d3f 34 , "age" // XI_HTTP_HEADER_AGE
xively 0:82702e998d3f 35 , "vary" // XI_HTTP_HEADER_VARY
xively 0:82702e998d3f 36 , "unknown" // XI_HTTP_HEADER_UNKNOWN, //!< !!!! this must be always on the last position
xively 0:82702e998d3f 37 };
xively 0:82702e998d3f 38
xively 0:82702e998d3f 39 static inline http_header_type_t classify_header( const char* header )
xively 0:82702e998d3f 40 {
xively 0:82702e998d3f 41 for( unsigned short i = 0; i < XI_HTTP_HEADER_COUNT - 1; ++i )
xively 0:82702e998d3f 42 {
xively 0:82702e998d3f 43 if( strcasecmp( header, XI_HTTP_TOKEN_NAMES[ i ] ) == 0 )
xively 0:82702e998d3f 44 return ( http_header_type_t ) i;
xively 0:82702e998d3f 45 }
xively 0:82702e998d3f 46
xively 0:82702e998d3f 47 return XI_HTTP_HEADER_UNKNOWN;
xively 0:82702e998d3f 48 }
xively 0:82702e998d3f 49
xively 0:82702e998d3f 50 const char* parse_http_status( http_response_t* response, const char* content )
xively 0:82702e998d3f 51 {
xively 0:82702e998d3f 52 // variables
xively 0:82702e998d3f 53 int c = 0;
xively 0:82702e998d3f 54
xively 0:82702e998d3f 55 // find the first occurrence of CRLF
xively 0:82702e998d3f 56 const char* header_end_ptr = strstr( content, XI_HTTP_CRLF );
xively 0:82702e998d3f 57
xively 0:82702e998d3f 58 // check continuation condition
xively 0:82702e998d3f 59 XI_CHECK_ZERO( header_end_ptr, XI_HTTP_STATUS_PARSE_ERROR );
xively 0:82702e998d3f 60
xively 0:82702e998d3f 61 // update the pointer
xively 0:82702e998d3f 62 header_end_ptr += 2;
xively 0:82702e998d3f 63
xively 0:82702e998d3f 64 // parse
xively 0:82702e998d3f 65 c = sscanf( content
xively 0:82702e998d3f 66 , SET_HTTP_STATUS_PATTERN(
xively 0:82702e998d3f 67 response->http_version1
xively 0:82702e998d3f 68 , response->http_version2
xively 0:82702e998d3f 69 , response->http_status
xively 0:82702e998d3f 70 , response->http_status_string ) );
xively 0:82702e998d3f 71
xively 0:82702e998d3f 72 // check if all arguments found
xively 0:82702e998d3f 73 XI_CHECK_CND( c != 4, XI_HTTP_STATUS_PARSE_ERROR );
xively 0:82702e998d3f 74
xively 0:82702e998d3f 75 // return updated ptr
xively 0:82702e998d3f 76 return header_end_ptr;
xively 0:82702e998d3f 77
xively 0:82702e998d3f 78 err_handling:
xively 0:82702e998d3f 79 return 0;
xively 0:82702e998d3f 80 }
xively 0:82702e998d3f 81
xively 0:82702e998d3f 82 const char* parse_http_header( http_response_t* response
xively 0:82702e998d3f 83 , const char* content )
xively 0:82702e998d3f 84 {
xively 0:82702e998d3f 85 // find the first occurrence of CRLF
xively 0:82702e998d3f 86 const char* header_end_ptr = strstr( content, XI_HTTP_CRLF );
xively 0:82702e998d3f 87 const char* header_name_end_ptr = strstr( content, ":" );
xively 0:82702e998d3f 88
xively 0:82702e998d3f 89 // check continuation condition
xively 0:82702e998d3f 90 XI_CHECK_ZERO( header_end_ptr, XI_HTTP_HEADER_PARSE_ERROR );
xively 0:82702e998d3f 91 XI_CHECK_ZERO( header_name_end_ptr, XI_HTTP_HEADER_PARSE_ERROR );
xively 0:82702e998d3f 92 XI_CHECK_CND( header_name_end_ptr > header_end_ptr, XI_HTTP_HEADER_PARSE_ERROR );
xively 0:82702e998d3f 93
xively 0:82702e998d3f 94 {
xively 0:82702e998d3f 95 int size = sizeof( response->http_headers[ response->http_headers_size ].name );
xively 0:82702e998d3f 96
xively 0:82702e998d3f 97 XI_CHECK_CND( header_name_end_ptr - content > size - 1, XI_HTTP_HEADER_PARSE_ERROR );
xively 0:82702e998d3f 98
xively 0:82702e998d3f 99 memcpy( response->http_headers[ response->http_headers_size ].name
xively 0:82702e998d3f 100 , content, XI_MIN( size - 1, header_name_end_ptr - content ) );
xively 0:82702e998d3f 101
xively 0:82702e998d3f 102 // set the guard
xively 0:82702e998d3f 103 XI_GUARD_EOS( response->http_headers[ response->http_headers_size ].name, size );
xively 0:82702e998d3f 104 }
xively 0:82702e998d3f 105
xively 0:82702e998d3f 106 // update the pointer
xively 0:82702e998d3f 107 header_name_end_ptr += 2;
xively 0:82702e998d3f 108
xively 0:82702e998d3f 109 {
xively 0:82702e998d3f 110 int size = sizeof( response->http_headers[ response->http_headers_size ].value );
xively 0:82702e998d3f 111
xively 0:82702e998d3f 112 XI_CHECK_CND( header_end_ptr - header_name_end_ptr > size - 1, XI_HTTP_HEADER_PARSE_ERROR );
xively 0:82702e998d3f 113
xively 0:82702e998d3f 114 memcpy( response->http_headers[ response->http_headers_size ].value
xively 0:82702e998d3f 115 , header_name_end_ptr, XI_MIN( size - 1, header_end_ptr - header_name_end_ptr ) );
xively 0:82702e998d3f 116
xively 0:82702e998d3f 117 // set the guard
xively 0:82702e998d3f 118 XI_GUARD_EOS( response->http_headers[ response->http_headers_size ].value, size );
xively 0:82702e998d3f 119 }
xively 0:82702e998d3f 120
xively 0:82702e998d3f 121 // @TODO change the complexity of the classify header
xively 0:82702e998d3f 122 // implementation now it's O( n*m ) it can be done in O( n )
xively 0:82702e998d3f 123 // using some sort of simple DFA
xively 0:82702e998d3f 124 // I'm working on a very simple Python DFA generator for C
xively 0:82702e998d3f 125 // but still this is a w.i.p. at the moment
xively 0:82702e998d3f 126
xively 0:82702e998d3f 127 // parse the header name
xively 0:82702e998d3f 128 {
xively 0:82702e998d3f 129 http_header_type_t ht = classify_header(
xively 0:82702e998d3f 130 response->http_headers[ response->http_headers_size ].name );
xively 0:82702e998d3f 131
xively 0:82702e998d3f 132 // accept headers that differs from unknown
xively 0:82702e998d3f 133 if( ht != XI_HTTP_HEADER_UNKNOWN )
xively 0:82702e998d3f 134 {
xively 0:82702e998d3f 135 response->http_headers_checklist[ ht ] =
xively 0:82702e998d3f 136 &response->http_headers[ response->http_headers_size ];
xively 0:82702e998d3f 137 }
xively 0:82702e998d3f 138
xively 0:82702e998d3f 139 // set header type
xively 0:82702e998d3f 140 response->http_headers[ response->http_headers_size ].header_type = ht;
xively 0:82702e998d3f 141
xively 0:82702e998d3f 142 // increment headers size and check if it's okay
xively 0:82702e998d3f 143 response->http_headers_size += 1;
xively 0:82702e998d3f 144
xively 0:82702e998d3f 145 XI_CHECK_CND( response->http_headers_size >= XI_HTTP_MAX_HEADERS
xively 0:82702e998d3f 146 , XI_HTTP_HEADER_PARSE_ERROR );
xively 0:82702e998d3f 147
xively 0:82702e998d3f 148 // update the pointer
xively 0:82702e998d3f 149 header_end_ptr += sizeof( XI_HTTP_CRLF ) - 1;
xively 0:82702e998d3f 150 }
xively 0:82702e998d3f 151
xively 0:82702e998d3f 152 return header_end_ptr;
xively 0:82702e998d3f 153
xively 0:82702e998d3f 154 err_handling:
xively 0:82702e998d3f 155 return 0;
xively 0:82702e998d3f 156 }
xively 0:82702e998d3f 157
xively 0:82702e998d3f 158 http_response_t* parse_http( http_response_t* response, const char* content )
xively 0:82702e998d3f 159 {
xively 0:82702e998d3f 160 memset( response, 0, sizeof( http_response_t ) );
xively 0:82702e998d3f 161
xively 0:82702e998d3f 162 // remember where is the end of header section
xively 0:82702e998d3f 163 const char* ptr_to_headers_end = strstr( content, XI_HTTP_CRLFX2 );
xively 0:82702e998d3f 164
xively 0:82702e998d3f 165 // check the continuation condition
xively 0:82702e998d3f 166 XI_CHECK_ZERO( ptr_to_headers_end, XI_HTTP_PARSE_ERROR );
xively 0:82702e998d3f 167
xively 0:82702e998d3f 168 // update the pointer
xively 0:82702e998d3f 169 ptr_to_headers_end += sizeof( XI_HTTP_CRLF ) - 1;
xively 0:82702e998d3f 170
xively 0:82702e998d3f 171 const char* payload_begin = ptr_to_headers_end + sizeof( XI_HTTP_CRLF ) - 1;
xively 0:82702e998d3f 172
xively 0:82702e998d3f 173 XI_CHECK_ZERO( payload_begin, XI_HTTP_PARSE_ERROR );
xively 0:82702e998d3f 174
xively 0:82702e998d3f 175 // parse status
xively 0:82702e998d3f 176 const char* ptr = parse_http_status( response, content );
xively 0:82702e998d3f 177
xively 0:82702e998d3f 178 // check the continuation condition
xively 0:82702e998d3f 179 XI_CHECK_ZERO( ptr, XI_HTTP_PARSE_ERROR );
xively 0:82702e998d3f 180
xively 0:82702e998d3f 181 // read the headers
xively 0:82702e998d3f 182 while( ( ptr = parse_http_header( response, ptr ) ) != '\0'
xively 0:82702e998d3f 183 && ptr != ptr_to_headers_end );
xively 0:82702e998d3f 184
xively 0:82702e998d3f 185 // if there was an error, forward it
xively 0:82702e998d3f 186 xi_err_t e = xi_get_last_error();
xively 0:82702e998d3f 187 XI_CHECK_CND( e != XI_NO_ERR, e );
xively 0:82702e998d3f 188
xively 0:82702e998d3f 189 // just copy the content
xively 0:82702e998d3f 190 strncpy( response->http_content, payload_begin, sizeof( response->http_content ) );
xively 0:82702e998d3f 191
xively 0:82702e998d3f 192 return response;
xively 0:82702e998d3f 193
xively 0:82702e998d3f 194 err_handling:
xively 0:82702e998d3f 195 return 0;
xively 0:82702e998d3f 196 }