├── .gitignore ├── config ├── README.md └── src ├── ngx_http_json.h ├── ngx_http_upsync_module.h ├── ngx_http_parser.h ├── ngx_http_json.c └── ngx_http_parser.c /.gitignore: -------------------------------------------------------------------------------- 1 | .settings/ 2 | 3 | # Generic ignore stuff 4 | .vagrant/* 5 | *.komodoproject 6 | .DS_Store 7 | ._* 8 | .svn 9 | .hg 10 | .*.swp 11 | .buildpath 12 | .project 13 | logs/ 14 | /.idea/ 15 | buildtmp 16 | # ctags 17 | *.tags 18 | .tags_sorted_by_file 19 | -------------------------------------------------------------------------------- /config: -------------------------------------------------------------------------------- 1 | ngx_addon_name=ngx_http_upsync_module 2 | 3 | ngx_feature_libs="-lm" 4 | 5 | ngx_module_incs=$ngx_addon_dir/src 6 | 7 | _HTTP_UPSYNC_SRCS="\ 8 | $ngx_addon_dir/src/ngx_http_upsync_module.c \ 9 | $ngx_addon_dir/src/ngx_http_json.c \ 10 | $ngx_addon_dir/src/ngx_http_parser.c \ 11 | " 12 | 13 | have=NGX_HTTP_UPSYNC . auto/have 14 | 15 | if test -n "$ngx_module_link"; then 16 | ngx_module_type=HTTP 17 | ngx_module_name=$ngx_addon_name 18 | ngx_module_srcs="$_HTTP_UPSYNC_SRCS" 19 | ngx_module_libs=$ngx_feature_libs 20 | . auto/module 21 | else 22 | NGX_ADDON_SRCS="$NGX_ADDON_SRCS $_HTTP_UPSYNC_SRCS" 23 | CORE_LIBS="$CORE_LIBS $ngx_feature_libs" 24 | CORE_INCS="$CORE_INCS $ngx_module_incs" 25 | HTTP_MODULES="$HTTP_MODULES $ngx_addon_name" 26 | fi 27 | 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## 简介 2 | 3 | 4 | 5 | nginx-upsync-module - Nginx C module, sync upstreams from consul、etcd and **zookeeper**, dynamiclly modify backend-servers attribute(weight, max_fails,...), needn't reload nginx. 6 | 7 | the project is based on [weibocom/nginx-upsync-module](https://github.com/weibocom/nginx-upsync-module),you can find more detail from it. 8 | 9 | nginx插件,支持在不reload nginx的情况下,更新upstream配置。upstream配置存储在etcd/zk/consul中. 10 | 11 | 因为zk不提供内置的rest http api,因此要使用[ezbz/Zookie 12 | ](https://github.com/ezbz/Zookie),本插件的json格式解析也是按照[ezbz/Zookie 13 | ](https://github.com/ezbz/Zookie)来的。 14 | 15 | 16 | 17 | upstream test { 18 | # fake server otherwise ngx_http_upstream will report error when startup 19 | server 127.0.0.1:11111; 20 | 21 | # all backend server will pull from consul when startup and will delete fake server 22 | upsync 192.168.3.56:12023/Zookie/tree?root=/nginx/upstreams/test upsync_timeout=6m upsync_interval=500ms upsync_type=zk strong_dependency=off; 23 | upsync_dump_path /usr/local/nginx/conf/servers/servers_test.conf; 24 | } 25 | 26 | server { 27 | listen 90; 28 | 29 | location = /proxy_test { 30 | proxy_pass http://test; 31 | } 32 | 33 | location = /upstream_show { 34 | upstream_show; 35 | } 36 | 37 | } 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /src/ngx_http_json.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2009 Dave Gamble 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | */ 22 | 23 | #ifndef cJSON__h 24 | #define cJSON__h 25 | 26 | #ifdef __cplusplus 27 | extern "C" 28 | { 29 | #endif 30 | 31 | /* cJSON Types: */ 32 | #define cJSON_False 0 33 | #define cJSON_True 1 34 | #define cJSON_NULL 2 35 | #define cJSON_Number 3 36 | #define cJSON_String 4 37 | #define cJSON_Array 5 38 | #define cJSON_Object 6 39 | 40 | #define cJSON_IsReference 256 41 | 42 | /* The cJSON structure: */ 43 | typedef struct cJSON { 44 | struct cJSON *next,*prev; /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */ 45 | struct cJSON *child; /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */ 46 | 47 | int type; /* The type of the item, as above. */ 48 | 49 | char *valuestring; /* The item's string, if type==cJSON_String */ 50 | int valueint; /* The item's number, if type==cJSON_Number */ 51 | double valuedouble; /* The item's number, if type==cJSON_Number */ 52 | 53 | char *string; /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */ 54 | } cJSON; 55 | 56 | typedef struct cJSON_Hooks { 57 | void *(*malloc_fn)(size_t sz); 58 | void (*free_fn)(void *ptr); 59 | } cJSON_Hooks; 60 | 61 | /* Supply malloc, realloc and free functions to cJSON */ 62 | extern void cJSON_InitHooks(cJSON_Hooks* hooks); 63 | 64 | 65 | /* Supply a block of JSON, and this returns a cJSON object you can interrogate. Call cJSON_Delete when finished. */ 66 | extern cJSON *cJSON_Parse(const char *value); 67 | /* Render a cJSON entity to text for transfer/storage. Free the char* when finished. */ 68 | extern char *cJSON_Print(cJSON *item); 69 | /* Render a cJSON entity to text for transfer/storage without any formatting. Free the char* when finished. */ 70 | extern char *cJSON_PrintUnformatted(cJSON *item); 71 | /* Delete a cJSON entity and all subentities. */ 72 | extern void cJSON_Delete(cJSON *c); 73 | 74 | /* Returns the number of items in an array (or object). */ 75 | extern int cJSON_GetArraySize(cJSON *array); 76 | /* Retrieve item number "item" from array "array". Returns NULL if unsuccessful. */ 77 | extern cJSON *cJSON_GetArrayItem(cJSON *array,int item); 78 | /* Get item "string" from object. Case insensitive. */ 79 | extern cJSON *cJSON_GetObjectItem(cJSON *object,const char *string); 80 | 81 | /* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */ 82 | extern const char *cJSON_GetErrorPtr(void); 83 | 84 | /* These calls create a cJSON item of the appropriate type. */ 85 | extern cJSON *cJSON_CreateNull(void); 86 | extern cJSON *cJSON_CreateTrue(void); 87 | extern cJSON *cJSON_CreateFalse(void); 88 | extern cJSON *cJSON_CreateBool(int b); 89 | extern cJSON *cJSON_CreateNumber(double num); 90 | extern cJSON *cJSON_CreateString(const char *string); 91 | extern cJSON *cJSON_CreateArray(void); 92 | extern cJSON *cJSON_CreateObject(void); 93 | 94 | /* These utilities create an Array of count items. */ 95 | extern cJSON *cJSON_CreateIntArray(int *numbers,int count); 96 | extern cJSON *cJSON_CreateFloatArray(float *numbers,int count); 97 | extern cJSON *cJSON_CreateDoubleArray(double *numbers,int count); 98 | extern cJSON *cJSON_CreateStringArray(const char **strings,int count); 99 | 100 | /* Append item to the specified array/object. */ 101 | extern void cJSON_AddItemToArray(cJSON *array, cJSON *item); 102 | extern void cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item); 103 | /* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */ 104 | extern void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item); 105 | extern void cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item); 106 | 107 | /* Remove/Detatch items from Arrays/Objects. */ 108 | extern cJSON *cJSON_DetachItemFromArray(cJSON *array,int which); 109 | extern void cJSON_DeleteItemFromArray(cJSON *array,int which); 110 | extern cJSON *cJSON_DetachItemFromObject(cJSON *object,const char *string); 111 | extern void cJSON_DeleteItemFromObject(cJSON *object,const char *string); 112 | 113 | /* Update array items. */ 114 | extern void cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem); 115 | extern void cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem); 116 | 117 | /* Duplicate a cJSON item */ 118 | extern cJSON *cJSON_Duplicate(cJSON *item,int recurse); 119 | /* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will 120 | need to be released. With recurse!=0, it will duplicate any children connected to the item. 121 | The item->next and ->prev pointers are always zero on return from Duplicate. */ 122 | 123 | /* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */ 124 | extern cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int require_null_terminated); 125 | 126 | /* Macros for creating things quickly. */ 127 | #define cJSON_AddNullToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateNull()) 128 | #define cJSON_AddTrueToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateTrue()) 129 | #define cJSON_AddFalseToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateFalse()) 130 | #define cJSON_AddBoolToObject(object,name,b) cJSON_AddItemToObject(object, name, cJSON_CreateBool(b)) 131 | #define cJSON_AddNumberToObject(object,name,n) cJSON_AddItemToObject(object, name, cJSON_CreateNumber(n)) 132 | #define cJSON_AddStringToObject(object,name,s) cJSON_AddItemToObject(object, name, cJSON_CreateString(s)) 133 | 134 | /* When assigning an integer value, it needs to be propagated to valuedouble too. */ 135 | #define cJSON_SetIntValue(object,val) ((object)?(object)->valueint=(object)->valuedouble=(val):(val)) 136 | 137 | #ifdef __cplusplus 138 | } 139 | #endif 140 | 141 | #endif 142 | -------------------------------------------------------------------------------- /src/ngx_http_upsync_module.h: -------------------------------------------------------------------------------- 1 | #ifndef _NGX_HTTP_UPSYNC_MODELE_H_INCLUDED_ 2 | #define _NGX_HTTP_UPSYNC_MODELE_H_INCLUDED_ 3 | 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include "ngx_http_json.h" 10 | #include "ngx_http_parser.h" 11 | 12 | 13 | #define ngx_strrchr(s1, c) strrchr((const char *) s1, (int) c) 14 | #define ngx_ftruncate(fd, offset) ftruncate(fd, offset) 15 | #define ngx_lseek(fd, offset, whence) lseek(fd, offset, whence) 16 | #define ngx_fgets(fp, offset, whence) fgets(fp, offset, whence) 17 | #define ngx_fopen(path, mode) fopen(path, mode) 18 | #define ngx_fclose(fp) fclose(fp) 19 | 20 | 21 | #define NGX_INDEX_HEARDER "X-Consul-Index" 22 | #define NGX_INDEX_HEARDER_LEN 14 23 | 24 | #define NGX_INDEX_ETCD_HEARDER "X-Etcd-Index" 25 | #define NGX_INDEX_ETCD_HEARDER_LEN 12 26 | 27 | #define NGX_MAX_HEADERS 20 28 | #define NGX_MAX_ELEMENT_SIZE 512 29 | 30 | #define NGX_DELAY_DELETE 75 * 1000 31 | 32 | #define NGX_ADD 0 33 | #define NGX_DEL 1 34 | 35 | #define NGX_PAGE_SIZE 4 * 1024 36 | #define NGX_PAGE_NUMBER 1024 37 | 38 | #define NGX_HTTP_RETRY_TIMES 3 39 | #define NGX_HTTP_SOCKET_TIMEOUT 1 40 | 41 | #define NGX_HTTP_LB_DEFAULT 0 42 | #define NGX_HTTP_LB_ROUNDROBIN 1 43 | #define NGX_HTTP_LB_IP_HASH 2 44 | #define NGX_HTTP_LB_LEAST_CONN 4 45 | #define NGX_HTTP_LB_HASH_MODULA 8 46 | #define NGX_HTTP_LB_HASH_KETAMA 16 47 | 48 | #if (NGX_HTTP_UPSTREAM_CHECK) 49 | 50 | extern ngx_uint_t ngx_http_upstream_check_add_dynamic_peer(ngx_pool_t *pool, 51 | ngx_http_upstream_srv_conf_t *uscf, ngx_addr_t *peer_addr); 52 | extern void ngx_http_upstream_check_delete_dynamic_peer(ngx_str_t *name, 53 | ngx_addr_t *peer_addr); 54 | 55 | #endif 56 | 57 | 58 | /******************************hash*********************************/ 59 | 60 | extern ngx_module_t ngx_http_upstream_hash_module; 61 | 62 | 63 | typedef struct { 64 | uint32_t hash; 65 | ngx_str_t *server; 66 | } ngx_http_upstream_chash_point_t; 67 | 68 | 69 | typedef struct { 70 | ngx_uint_t number; 71 | ngx_http_upstream_chash_point_t point[1]; 72 | } ngx_http_upstream_chash_points_t; 73 | 74 | 75 | typedef struct { 76 | ngx_http_complex_value_t key; 77 | ngx_http_upstream_chash_points_t *points; 78 | } ngx_http_upstream_hash_srv_conf_t; 79 | 80 | /****************************hash_end*******************************/ 81 | 82 | 83 | static int ngx_libc_cdecl ngx_http_upsync_chash_cmp_points(const void *one, 84 | const void *two); 85 | static ngx_int_t ngx_http_upsync_chash_init(ngx_http_upstream_srv_conf_t *uscf, 86 | ngx_http_upstream_rr_peers_t *tmp_peers); 87 | static ngx_int_t ngx_http_upsync_del_chash_peer( 88 | ngx_http_upstream_srv_conf_t *uscf); 89 | 90 | 91 | static int ngx_libc_cdecl 92 | ngx_http_upsync_chash_cmp_points(const void *one, const void *two) 93 | { 94 | ngx_http_upstream_chash_point_t *first = 95 | (ngx_http_upstream_chash_point_t *) one; 96 | ngx_http_upstream_chash_point_t *second = 97 | (ngx_http_upstream_chash_point_t *) two; 98 | 99 | if (first->hash < second->hash) { 100 | return -1; 101 | 102 | } else if (first->hash > second->hash) { 103 | return 1; 104 | 105 | } else { 106 | return 0; 107 | } 108 | } 109 | 110 | 111 | static ngx_int_t 112 | ngx_http_upsync_chash_init(ngx_http_upstream_srv_conf_t *uscf, 113 | ngx_http_upstream_rr_peers_t *tmp_peers) 114 | { 115 | size_t new_size; 116 | size_t host_len, port_len; 117 | u_char *host, *port, c; 118 | uint32_t hash, base_hash; 119 | ngx_str_t *server; 120 | ngx_uint_t npoints, new_npoints; 121 | ngx_uint_t i, j; 122 | ngx_http_upstream_rr_peer_t *peer; 123 | ngx_http_upstream_rr_peers_t *peers; 124 | ngx_http_upstream_chash_points_t *points; 125 | ngx_http_upstream_hash_srv_conf_t *hcf; 126 | union { 127 | uint32_t value; 128 | u_char byte[4]; 129 | } prev_hash; 130 | 131 | hcf = ngx_http_conf_upstream_srv_conf(uscf, ngx_http_upstream_hash_module); 132 | if(hcf->points == NULL) { 133 | return 0; 134 | } 135 | 136 | peers = uscf->peer.data; 137 | if (tmp_peers != NULL) { 138 | new_npoints = peers->total_weight * 160; 139 | 140 | new_size = sizeof(ngx_http_upstream_chash_points_t) 141 | + sizeof(ngx_http_upstream_chash_point_t) * (new_npoints - 1); 142 | 143 | points = ngx_calloc(new_size, ngx_cycle->log); 144 | if (points == NULL ) { 145 | return NGX_ERROR; 146 | } 147 | ngx_free(hcf->points); /* free old points */ 148 | hcf->points = points; 149 | 150 | for (peer = peers->peer; peer; peer = peer->next) { 151 | server = &peer->server; 152 | 153 | /* 154 | * Hash expression is compatible with Cache::Memcached::Fast: 155 | * crc32(HOST \0 PORT PREV_HASH). 156 | */ 157 | 158 | if (server->len >= 5 159 | && ngx_strncasecmp(server->data, (u_char *) "unix:", 5) == 0) 160 | { 161 | host = server->data + 5; 162 | host_len = server->len - 5; 163 | port = NULL; 164 | port_len = 0; 165 | goto done; 166 | } 167 | 168 | for (j = 0; j < server->len; j++) { 169 | c = server->data[server->len - j - 1]; 170 | 171 | if (c == ':') { 172 | host = server->data; 173 | host_len = server->len - j - 1; 174 | port = server->data + server->len - j; 175 | port_len = j; 176 | goto done; 177 | } 178 | 179 | if (c < '0' || c > '9') { 180 | break; 181 | } 182 | } 183 | 184 | host = server->data; 185 | host_len = server->len; 186 | port = NULL; 187 | port_len = 0; 188 | 189 | done: 190 | 191 | ngx_crc32_init(base_hash); 192 | ngx_crc32_update(&base_hash, host, host_len); 193 | ngx_crc32_update(&base_hash, (u_char *) "", 1); 194 | ngx_crc32_update(&base_hash, port, port_len); 195 | 196 | prev_hash.value = 0; 197 | npoints = peer->weight * 160; 198 | 199 | for (j = 0; j < npoints; j++) { 200 | hash = base_hash; 201 | 202 | ngx_crc32_update(&hash, prev_hash.byte, 4); 203 | ngx_crc32_final(hash); 204 | 205 | points->point[points->number].hash = hash; 206 | points->point[points->number].server = server; 207 | points->number++; 208 | 209 | #if (NGX_HAVE_LITTLE_ENDIAN) 210 | prev_hash.value = hash; 211 | #else 212 | prev_hash.byte[0] = (u_char) (hash & 0xff); 213 | prev_hash.byte[1] = (u_char) ((hash >> 8) & 0xff); 214 | prev_hash.byte[2] = (u_char) ((hash >> 16) & 0xff); 215 | prev_hash.byte[3] = (u_char) ((hash >> 24) & 0xff); 216 | #endif 217 | } 218 | } 219 | 220 | } else { 221 | new_npoints = peers->total_weight * 160; 222 | 223 | new_size = sizeof(ngx_http_upstream_chash_points_t) 224 | + sizeof(ngx_http_upstream_chash_point_t) * (new_npoints - 1); 225 | 226 | points = ngx_calloc(new_size, ngx_cycle->log); 227 | if (points == NULL ) { 228 | return NGX_ERROR; 229 | } 230 | 231 | ngx_memcpy(points, hcf->points, new_size); 232 | ngx_pfree(ngx_cycle->pool, hcf->points); 233 | 234 | hcf->points = points; 235 | 236 | return NGX_OK; 237 | } 238 | 239 | ngx_qsort(points->point, 240 | points->number, 241 | sizeof(ngx_http_upstream_chash_point_t), 242 | ngx_http_upsync_chash_cmp_points); 243 | 244 | for (i = 0, j = 1; j < points->number; j++) { 245 | if (points->point[i].hash != points->point[j].hash) { 246 | points->point[++i] = points->point[j]; 247 | } 248 | } 249 | 250 | points->number = i + 1; 251 | 252 | return NGX_OK; 253 | } 254 | 255 | 256 | static ngx_int_t 257 | ngx_http_upsync_del_chash_peer(ngx_http_upstream_srv_conf_t *uscf) 258 | { 259 | size_t host_len, port_len; 260 | u_char *host, *port, c; 261 | uint32_t hash, base_hash; 262 | ngx_str_t *server; 263 | ngx_uint_t npoints, i, j; 264 | ngx_http_upstream_rr_peer_t *peer; 265 | ngx_http_upstream_rr_peers_t *peers; 266 | ngx_http_upstream_chash_points_t *points; 267 | ngx_http_upstream_hash_srv_conf_t *hcf; 268 | union { 269 | uint32_t value; 270 | u_char byte[4]; 271 | } prev_hash; 272 | 273 | hcf = ngx_http_conf_upstream_srv_conf(uscf, ngx_http_upstream_hash_module); 274 | if(hcf->points == NULL) { 275 | return 0; 276 | } 277 | 278 | peers = uscf->peer.data; 279 | 280 | points = hcf->points; 281 | points->number = 0; 282 | 283 | for (peer = peers->peer; peer; peer = peer->next) { 284 | server = &peer->server; 285 | 286 | /* 287 | * Hash expression is compatible with Cache::Memcached::Fast: 288 | * crc32(HOST \0 PORT PREV_HASH). 289 | */ 290 | 291 | if (server->len >= 5 292 | && ngx_strncasecmp(server->data, (u_char *) "unix:", 5) == 0) 293 | { 294 | host = server->data + 5; 295 | host_len = server->len - 5; 296 | port = NULL; 297 | port_len = 0; 298 | goto done; 299 | } 300 | 301 | for (j = 0; j < server->len; j++) { 302 | c = server->data[server->len - j - 1]; 303 | 304 | if (c == ':') { 305 | host = server->data; 306 | host_len = server->len - j - 1; 307 | port = server->data + server->len - j; 308 | port_len = j; 309 | goto done; 310 | } 311 | 312 | if (c < '0' || c > '9') { 313 | break; 314 | } 315 | } 316 | 317 | host = server->data; 318 | host_len = server->len; 319 | port = NULL; 320 | port_len = 0; 321 | 322 | done: 323 | 324 | ngx_crc32_init(base_hash); 325 | ngx_crc32_update(&base_hash, host, host_len); 326 | ngx_crc32_update(&base_hash, (u_char *) "", 1); 327 | ngx_crc32_update(&base_hash, port, port_len); 328 | 329 | prev_hash.value = 0; 330 | npoints = peer->weight * 160; 331 | 332 | for (j = 0; j < npoints; j++) { 333 | hash = base_hash; 334 | 335 | ngx_crc32_update(&hash, prev_hash.byte, 4); 336 | ngx_crc32_final(hash); 337 | 338 | points->point[points->number].hash = hash; 339 | points->point[points->number].server = server; 340 | points->number++; 341 | 342 | #if (NGX_HAVE_LITTLE_ENDIAN) 343 | prev_hash.value = hash; 344 | #else 345 | prev_hash.byte[0] = (u_char) (hash & 0xff); 346 | prev_hash.byte[1] = (u_char) ((hash >> 8) & 0xff); 347 | prev_hash.byte[2] = (u_char) ((hash >> 16) & 0xff); 348 | prev_hash.byte[3] = (u_char) ((hash >> 24) & 0xff); 349 | #endif 350 | } 351 | } 352 | 353 | ngx_qsort(points->point, 354 | points->number, 355 | sizeof(ngx_http_upstream_chash_point_t), 356 | ngx_http_upsync_chash_cmp_points); 357 | 358 | for (i = 0, j = 1; j < points->number; j++) { 359 | if (points->point[i].hash != points->point[j].hash) { 360 | points->point[++i] = points->point[j]; 361 | } 362 | } 363 | 364 | points->number = i + 1; 365 | 366 | return NGX_OK; 367 | } 368 | 369 | 370 | #endif //_NGX_HTTP_UPSYNC_MODELE_H_INCLUDED_ 371 | -------------------------------------------------------------------------------- /src/ngx_http_parser.h: -------------------------------------------------------------------------------- 1 | /* Copyright Joyent, Inc. and other Node contributors. All rights reserved. 2 | * 3 | * Permission is hereby granted, free of charge, to any person obtaining a copy 4 | * of this software and associated documentation files (the "Software"), to 5 | * deal in the Software without restriction, including without limitation the 6 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | * sell copies of the Software, and to permit persons to whom the Software is 8 | * furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in 11 | * all copies or substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 | * IN THE SOFTWARE. 20 | */ 21 | #ifndef http_parser_h 22 | #define http_parser_h 23 | #ifdef __cplusplus 24 | extern "C" { 25 | #endif 26 | 27 | /* Also update SONAME in the Makefile whenever you change these. */ 28 | #define HTTP_PARSER_VERSION_MAJOR 2 29 | #define HTTP_PARSER_VERSION_MINOR 4 30 | #define HTTP_PARSER_VERSION_PATCH 2 31 | 32 | #include 33 | #if defined(_WIN32) && !defined(__MINGW32__) && (!defined(_MSC_VER) || _MSC_VER<1600) 34 | #include 35 | #include 36 | typedef __int8 int8_t; 37 | typedef unsigned __int8 uint8_t; 38 | typedef __int16 int16_t; 39 | typedef unsigned __int16 uint16_t; 40 | typedef __int32 int32_t; 41 | typedef unsigned __int32 uint32_t; 42 | typedef __int64 int64_t; 43 | typedef unsigned __int64 uint64_t; 44 | #else 45 | #include 46 | #endif 47 | 48 | /* Compile with -DHTTP_PARSER_STRICT=0 to make less checks, but run 49 | * faster 50 | */ 51 | #ifndef HTTP_PARSER_STRICT 52 | # define HTTP_PARSER_STRICT 1 53 | #endif 54 | 55 | /* Maximium header size allowed. If the macro is not defined 56 | * before including this header then the default is used. To 57 | * change the maximum header size, define the macro in the build 58 | * environment (e.g. -DHTTP_MAX_HEADER_SIZE=). To remove 59 | * the effective limit on the size of the header, define the macro 60 | * to a very large number (e.g. -DHTTP_MAX_HEADER_SIZE=0x7fffffff) 61 | */ 62 | #ifndef HTTP_MAX_HEADER_SIZE 63 | # define HTTP_MAX_HEADER_SIZE (80*1024) 64 | #endif 65 | 66 | typedef struct http_parser http_parser; 67 | typedef struct http_parser_settings http_parser_settings; 68 | 69 | 70 | /* Callbacks should return non-zero to indicate an error. The parser will 71 | * then halt execution. 72 | * 73 | * The one exception is on_headers_complete. In a HTTP_RESPONSE parser 74 | * returning '1' from on_headers_complete will tell the parser that it 75 | * should not expect a body. This is used when receiving a response to a 76 | * HEAD request which may contain 'Content-Length' or 'Transfer-Encoding: 77 | * chunked' headers that indicate the presence of a body. 78 | * 79 | * http_data_cb does not return data chunks. It will be called arbitrarily 80 | * many times for each string. E.G. you might get 10 callbacks for "on_url" 81 | * each providing just a few characters more data. 82 | */ 83 | typedef int (*http_data_cb) (http_parser*, const char *at, size_t length); 84 | typedef int (*http_cb) (http_parser*); 85 | 86 | 87 | /* Request Methods */ 88 | #define HTTP_METHOD_MAP(XX) \ 89 | XX(0, DELETE, DELETE) \ 90 | XX(1, GET, GET) \ 91 | XX(2, HEAD, HEAD) \ 92 | XX(3, POST, POST) \ 93 | XX(4, PUT, PUT) \ 94 | /* pathological */ \ 95 | XX(5, CONNECT, CONNECT) \ 96 | XX(6, OPTIONS, OPTIONS) \ 97 | XX(7, TRACE, TRACE) \ 98 | /* webdav */ \ 99 | XX(8, COPY, COPY) \ 100 | XX(9, LOCK, LOCK) \ 101 | XX(10, MKCOL, MKCOL) \ 102 | XX(11, MOVE, MOVE) \ 103 | XX(12, PROPFIND, PROPFIND) \ 104 | XX(13, PROPPATCH, PROPPATCH) \ 105 | XX(14, SEARCH, SEARCH) \ 106 | XX(15, UNLOCK, UNLOCK) \ 107 | /* subversion */ \ 108 | XX(16, REPORT, REPORT) \ 109 | XX(17, MKACTIVITY, MKACTIVITY) \ 110 | XX(18, CHECKOUT, CHECKOUT) \ 111 | XX(19, MERGE, MERGE) \ 112 | /* upnp */ \ 113 | XX(20, MSEARCH, M-SEARCH) \ 114 | XX(21, NOTIFY, NOTIFY) \ 115 | XX(22, SUBSCRIBE, SUBSCRIBE) \ 116 | XX(23, UNSUBSCRIBE, UNSUBSCRIBE) \ 117 | /* RFC-5789 */ \ 118 | XX(24, PATCH, PATCH) \ 119 | XX(25, PURGE, PURGE) \ 120 | /* CalDAV */ \ 121 | XX(26, MKCALENDAR, MKCALENDAR) \ 122 | 123 | enum http_method 124 | { 125 | #define XX(num, name, string) HTTP_##name = num, 126 | HTTP_METHOD_MAP(XX) 127 | #undef XX 128 | }; 129 | 130 | 131 | enum http_parser_type { HTTP_REQUEST, HTTP_RESPONSE, HTTP_BOTH }; 132 | 133 | 134 | /* Flag values for http_parser.flags field */ 135 | enum flags 136 | { F_CHUNKED = 1 << 0 137 | , F_CONNECTION_KEEP_ALIVE = 1 << 1 138 | , F_CONNECTION_CLOSE = 1 << 2 139 | , F_CONNECTION_UPGRADE = 1 << 3 140 | , F_TRAILING = 1 << 4 141 | , F_UPGRADE = 1 << 5 142 | , F_SKIPBODY = 1 << 6 143 | }; 144 | 145 | 146 | /* Map for errno-related constants 147 | * 148 | * The provided argument should be a macro that takes 2 arguments. 149 | */ 150 | #define HTTP_ERRNO_MAP(XX) \ 151 | /* No error */ \ 152 | XX(OK, "success") \ 153 | \ 154 | /* Callback-related errors */ \ 155 | XX(CB_message_begin, "the on_message_begin callback failed") \ 156 | XX(CB_url, "the on_url callback failed") \ 157 | XX(CB_header_field, "the on_header_field callback failed") \ 158 | XX(CB_header_value, "the on_header_value callback failed") \ 159 | XX(CB_headers_complete, "the on_headers_complete callback failed") \ 160 | XX(CB_body, "the on_body callback failed") \ 161 | XX(CB_message_complete, "the on_message_complete callback failed") \ 162 | XX(CB_status, "the on_status callback failed") \ 163 | \ 164 | /* Parsing-related errors */ \ 165 | XX(INVALID_EOF_STATE, "stream ended at an unexpected time") \ 166 | XX(HEADER_OVERFLOW, \ 167 | "too many header bytes seen; overflow detected") \ 168 | XX(CLOSED_CONNECTION, \ 169 | "data received after completed connection: close message") \ 170 | XX(INVALID_VERSION, "invalid HTTP version") \ 171 | XX(INVALID_STATUS, "invalid HTTP status code") \ 172 | XX(INVALID_METHOD, "invalid HTTP method") \ 173 | XX(INVALID_URL, "invalid URL") \ 174 | XX(INVALID_HOST, "invalid host") \ 175 | XX(INVALID_PORT, "invalid port") \ 176 | XX(INVALID_PATH, "invalid path") \ 177 | XX(INVALID_QUERY_STRING, "invalid query string") \ 178 | XX(INVALID_FRAGMENT, "invalid fragment") \ 179 | XX(LF_EXPECTED, "LF character expected") \ 180 | XX(INVALID_HEADER_TOKEN, "invalid character in header") \ 181 | XX(INVALID_CONTENT_LENGTH, \ 182 | "invalid character in content-length header") \ 183 | XX(INVALID_CHUNK_SIZE, \ 184 | "invalid character in chunk size header") \ 185 | XX(INVALID_CONSTANT, "invalid constant string") \ 186 | XX(INVALID_INTERNAL_STATE, "encountered unexpected internal state")\ 187 | XX(STRICT, "strict mode assertion failed") \ 188 | XX(PAUSED, "parser is paused") \ 189 | XX(UNKNOWN, "an unknown error occurred") 190 | 191 | 192 | /* Define HPE_* values for each errno value above */ 193 | #define HTTP_ERRNO_GEN(n, s) HPE_##n, 194 | enum http_errno { 195 | HTTP_ERRNO_MAP(HTTP_ERRNO_GEN) 196 | }; 197 | #undef HTTP_ERRNO_GEN 198 | 199 | 200 | /* Get an http_errno value from an http_parser */ 201 | #define HTTP_PARSER_ERRNO(p) ((enum http_errno) (p)->http_errno) 202 | 203 | 204 | struct http_parser { 205 | /** PRIVATE **/ 206 | unsigned int type : 2; /* enum http_parser_type */ 207 | unsigned int flags : 7; /* F_* values from 'flags' enum; semi-public */ 208 | unsigned int state : 7; /* enum state from http_parser.c */ 209 | unsigned int header_state : 8; /* enum header_state from http_parser.c */ 210 | unsigned int index : 8; /* index into current matcher */ 211 | 212 | uint32_t nread; /* # bytes read in various scenarios */ 213 | uint64_t content_length; /* # bytes in body (0 if no Content-Length header) */ 214 | 215 | /** READ-ONLY **/ 216 | unsigned short http_major; 217 | unsigned short http_minor; 218 | unsigned int status_code : 16; /* responses only */ 219 | unsigned int method : 8; /* requests only */ 220 | unsigned int http_errno : 7; 221 | 222 | /* 1 = Upgrade header was present and the parser has exited because of that. 223 | * 0 = No upgrade header present. 224 | * Should be checked when http_parser_execute() returns in addition to 225 | * error checking. 226 | */ 227 | unsigned int upgrade : 1; 228 | 229 | /** PUBLIC **/ 230 | void *data; /* A pointer to get hook to the "connection" or "socket" object */ 231 | }; 232 | 233 | 234 | struct http_parser_settings { 235 | http_cb on_message_begin; 236 | http_data_cb on_url; 237 | http_data_cb on_status; 238 | http_data_cb on_header_field; 239 | http_data_cb on_header_value; 240 | http_cb on_headers_complete; 241 | http_data_cb on_body; 242 | http_cb on_message_complete; 243 | }; 244 | 245 | 246 | enum http_parser_url_fields 247 | { UF_SCHEMA = 0 248 | , UF_HOST = 1 249 | , UF_PORT = 2 250 | , UF_PATH = 3 251 | , UF_QUERY = 4 252 | , UF_FRAGMENT = 5 253 | , UF_USERINFO = 6 254 | , UF_MAX = 7 255 | }; 256 | 257 | 258 | /* Result structure for http_parser_parse_url(). 259 | * 260 | * Callers should index into field_data[] with UF_* values iff field_set 261 | * has the relevant (1 << UF_*) bit set. As a courtesy to clients (and 262 | * because we probably have padding left over), we convert any port to 263 | * a uint16_t. 264 | */ 265 | struct http_parser_url { 266 | uint16_t field_set; /* Bitmask of (1 << UF_*) values */ 267 | uint16_t port; /* Converted UF_PORT string */ 268 | 269 | struct { 270 | uint16_t off; /* Offset into buffer in which field starts */ 271 | uint16_t len; /* Length of run in buffer */ 272 | } field_data[UF_MAX]; 273 | }; 274 | 275 | 276 | /* Returns the library version. Bits 16-23 contain the major version number, 277 | * bits 8-15 the minor version number and bits 0-7 the patch level. 278 | * Usage example: 279 | * 280 | * unsigned long version = http_parser_version(); 281 | * unsigned major = (version >> 16) & 255; 282 | * unsigned minor = (version >> 8) & 255; 283 | * unsigned patch = version & 255; 284 | * printf("http_parser v%u.%u.%u\n", major, minor, patch); 285 | */ 286 | unsigned long http_parser_version(void); 287 | 288 | void http_parser_init(http_parser *parser, enum http_parser_type type); 289 | 290 | 291 | /* Initialize http_parser_settings members to 0 292 | */ 293 | void http_parser_settings_init(http_parser_settings *settings); 294 | 295 | 296 | /* Executes the parser. Returns number of parsed bytes. Sets 297 | * `parser->http_errno` on error. */ 298 | size_t http_parser_execute(http_parser *parser, 299 | const http_parser_settings *settings, 300 | const char *data, 301 | size_t len); 302 | 303 | 304 | /* If http_should_keep_alive() in the on_headers_complete or 305 | * on_message_complete callback returns 0, then this should be 306 | * the last message on the connection. 307 | * If you are the server, respond with the "Connection: close" header. 308 | * If you are the client, close the connection. 309 | */ 310 | int http_should_keep_alive(const http_parser *parser); 311 | 312 | /* Returns a string version of the HTTP method. */ 313 | const char *http_method_str(enum http_method m); 314 | 315 | /* Return a string name of the given error */ 316 | const char *http_errno_name(enum http_errno err); 317 | 318 | /* Return a string description of the given error */ 319 | const char *http_errno_description(enum http_errno err); 320 | 321 | /* Parse a URL; return nonzero on failure */ 322 | int http_parser_parse_url(const char *buf, size_t buflen, 323 | int is_connect, 324 | struct http_parser_url *u); 325 | 326 | /* Pause or un-pause the parser; a nonzero value pauses */ 327 | void http_parser_pause(http_parser *parser, int paused); 328 | 329 | /* Checks if this is the final chunk of the body. */ 330 | int http_body_is_final(const http_parser *parser); 331 | 332 | #ifdef __cplusplus 333 | } 334 | #endif 335 | #endif 336 | -------------------------------------------------------------------------------- /src/ngx_http_json.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2009 Dave Gamble 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | */ 22 | 23 | /* cJSON */ 24 | /* JSON parser in C. */ 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include "ngx_http_json.h" 34 | 35 | static const char *ep; 36 | 37 | const char *cJSON_GetErrorPtr(void) {return ep;} 38 | 39 | static int cJSON_strcasecmp(const char *s1,const char *s2) 40 | { 41 | if (!s1) return (s1==s2)?0:1;if (!s2) return 1; 42 | for(; tolower(*s1) == tolower(*s2); ++s1, ++s2) if(*s1 == 0) return 0; 43 | return tolower(*(const unsigned char *)s1) - tolower(*(const unsigned char *)s2); 44 | } 45 | 46 | static void *(*cJSON_malloc)(size_t sz) = malloc; 47 | static void (*cJSON_free)(void *ptr) = free; 48 | 49 | static char* cJSON_strdup(const char* str) 50 | { 51 | size_t len; 52 | char* copy; 53 | 54 | len = strlen(str) + 1; 55 | if (!(copy = (char*)cJSON_malloc(len))) return 0; 56 | memcpy(copy,str,len); 57 | return copy; 58 | } 59 | 60 | void cJSON_InitHooks(cJSON_Hooks* hooks) 61 | { 62 | if (!hooks) { /* Reset hooks */ 63 | cJSON_malloc = malloc; 64 | cJSON_free = free; 65 | return; 66 | } 67 | 68 | cJSON_malloc = (hooks->malloc_fn)?hooks->malloc_fn:malloc; 69 | cJSON_free = (hooks->free_fn)?hooks->free_fn:free; 70 | } 71 | 72 | /* Internal constructor. */ 73 | static cJSON *cJSON_New_Item(void) 74 | { 75 | cJSON* node = (cJSON*)cJSON_malloc(sizeof(cJSON)); 76 | if (node) memset(node,0,sizeof(cJSON)); 77 | return node; 78 | } 79 | 80 | /* Delete a cJSON structure. */ 81 | void cJSON_Delete(cJSON *c) 82 | { 83 | cJSON *next; 84 | while (c) 85 | { 86 | next=c->next; 87 | if (!(c->type&cJSON_IsReference) && c->child) cJSON_Delete(c->child); 88 | if (!(c->type&cJSON_IsReference) && c->valuestring) cJSON_free(c->valuestring); 89 | if (c->string) cJSON_free(c->string); 90 | cJSON_free(c); 91 | c=next; 92 | } 93 | } 94 | 95 | /* Parse the input text to generate a number, and populate the result into item. */ 96 | static const char *parse_number(cJSON *item,const char *num) 97 | { 98 | double n=0,sign=1,scale=0;int subscale=0,signsubscale=1; 99 | 100 | /* Could use sscanf for this? */ 101 | if (*num=='-') sign=-1,num++; /* Has sign? */ 102 | if (*num=='0') num++; /* is zero */ 103 | if (*num>='1' && *num<='9') do n=(n*10.0)+(*num++ -'0'); while (*num>='0' && *num<='9'); /* Number? */ 104 | if (*num=='.' && num[1]>='0' && num[1]<='9') {num++; do n=(n*10.0)+(*num++ -'0'),scale--; while (*num>='0' && *num<='9');} /* Fractional part? */ 105 | if (*num=='e' || *num=='E') /* Exponent? */ 106 | { num++;if (*num=='+') num++; else if (*num=='-') signsubscale=-1,num++; /* With sign? */ 107 | while (*num>='0' && *num<='9') subscale=(subscale*10)+(*num++ - '0'); /* Number? */ 108 | } 109 | 110 | n=sign*n*pow(10.0,(scale+subscale*signsubscale)); /* number = +/- number.fraction * 10^+/- exponent */ 111 | 112 | item->valuedouble=n; 113 | item->valueint=(int)n; 114 | item->type=cJSON_Number; 115 | return num; 116 | } 117 | 118 | /* Render the number nicely from the given item into a string. */ 119 | static char *print_number(cJSON *item) 120 | { 121 | char *str; 122 | double d=item->valuedouble; 123 | if (fabs(((double)item->valueint)-d)<=DBL_EPSILON && d<=INT_MAX && d>=INT_MIN) 124 | { 125 | str=(char*)cJSON_malloc(21); /* 2^64+1 can be represented in 21 chars. */ 126 | if (str) sprintf(str,"%d",item->valueint); 127 | } 128 | else 129 | { 130 | str=(char*)cJSON_malloc(64); /* This is a nice tradeoff. */ 131 | if (str) 132 | { 133 | if (fabs(floor(d)-d)<=DBL_EPSILON && fabs(d)<1.0e60)sprintf(str,"%.0f",d); 134 | else if (fabs(d)<1.0e-6 || fabs(d)>1.0e9) sprintf(str,"%e",d); 135 | else sprintf(str,"%f",d); 136 | } 137 | } 138 | return str; 139 | } 140 | 141 | /* Parse the input text into an unescaped cstring, and populate item. */ 142 | static const unsigned char firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; 143 | static const char *parse_string(cJSON *item,const char *str) 144 | { 145 | const char *ptr=str+1;char *ptr2;char *out;int len=0;unsigned uc,uc2; 146 | if (*str!='\"') {ep=str;return 0;} /* not a string! */ 147 | 148 | while (*ptr!='\"' && *ptr && ++len) if (*ptr++ == '\\') ptr++; /* Skip escaped quotes. */ 149 | 150 | out=(char*)cJSON_malloc(len+1); /* This is how long we need for the string, roughly. */ 151 | if (!out) return 0; 152 | 153 | ptr=str+1;ptr2=out; 154 | while (*ptr!='\"' && *ptr) 155 | { 156 | if (*ptr!='\\') *ptr2++=*ptr++; 157 | else 158 | { 159 | ptr++; 160 | switch (*ptr) 161 | { 162 | case 'b': *ptr2++='\b'; break; 163 | case 'f': *ptr2++='\f'; break; 164 | case 'n': *ptr2++='\n'; break; 165 | case 'r': *ptr2++='\r'; break; 166 | case 't': *ptr2++='\t'; break; 167 | case 'u': /* transcode utf16 to utf8. */ 168 | sscanf(ptr+1,"%4x",&uc);ptr+=4; /* get the unicode char. */ 169 | 170 | if ((uc>=0xDC00 && uc<=0xDFFF) || uc==0) break; /* check for invalid. */ 171 | 172 | if (uc>=0xD800 && uc<=0xDBFF) /* UTF16 surrogate pairs. */ 173 | { 174 | if (ptr[1]!='\\' || ptr[2]!='u') break; /* missing second-half of surrogate. */ 175 | sscanf(ptr+3,"%4x",&uc2);ptr+=6; 176 | if (uc2<0xDC00 || uc2>0xDFFF) break; /* invalid second-half of surrogate. */ 177 | uc=0x10000 + (((uc&0x3FF)<<10) | (uc2&0x3FF)); 178 | } 179 | 180 | len=4;if (uc<0x80) len=1;else if (uc<0x800) len=2;else if (uc<0x10000) len=3; ptr2+=len; 181 | 182 | switch (len) { 183 | case 4: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6; 184 | case 3: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6; 185 | case 2: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6; 186 | case 1: *--ptr2 =(uc | firstByteMark[len]); 187 | } 188 | ptr2+=len; 189 | break; 190 | default: *ptr2++=*ptr; break; 191 | } 192 | ptr++; 193 | } 194 | } 195 | *ptr2=0; 196 | if (*ptr=='\"') ptr++; 197 | item->valuestring=out; 198 | item->type=cJSON_String; 199 | return ptr; 200 | } 201 | 202 | /* Render the cstring provided to an escaped version that can be printed. */ 203 | static char *print_string_ptr(const char *str) 204 | { 205 | const char *ptr;char *ptr2,*out;int len=0;unsigned char token; 206 | 207 | if (!str) return cJSON_strdup(""); 208 | ptr=str;while ((token=*ptr) && ++len) {if (strchr("\"\\\b\f\n\r\t",token)) len++; else if (token<32) len+=5;ptr++;} 209 | 210 | out=(char*)cJSON_malloc(len+3); 211 | if (!out) return 0; 212 | 213 | ptr2=out;ptr=str; 214 | *ptr2++='\"'; 215 | while (*ptr) 216 | { 217 | if ((unsigned char)*ptr>31 && *ptr!='\"' && *ptr!='\\') *ptr2++=*ptr++; 218 | else 219 | { 220 | *ptr2++='\\'; 221 | switch (token=*ptr++) 222 | { 223 | case '\\': *ptr2++='\\'; break; 224 | case '\"': *ptr2++='\"'; break; 225 | case '\b': *ptr2++='b'; break; 226 | case '\f': *ptr2++='f'; break; 227 | case '\n': *ptr2++='n'; break; 228 | case '\r': *ptr2++='r'; break; 229 | case '\t': *ptr2++='t'; break; 230 | default: sprintf(ptr2,"u%04x",token);ptr2+=5; break; /* escape and print */ 231 | } 232 | } 233 | } 234 | *ptr2++='\"';*ptr2++=0; 235 | return out; 236 | } 237 | /* Invote print_string_ptr (which is useful) on an item. */ 238 | static char *print_string(cJSON *item) {return print_string_ptr(item->valuestring);} 239 | 240 | /* Predeclare these prototypes. */ 241 | static const char *parse_value(cJSON *item,const char *value); 242 | static char *print_value(cJSON *item,int depth,int fmt); 243 | static const char *parse_array(cJSON *item,const char *value); 244 | static char *print_array(cJSON *item,int depth,int fmt); 245 | static const char *parse_object(cJSON *item,const char *value); 246 | static char *print_object(cJSON *item,int depth,int fmt); 247 | 248 | /* Utility to jump whitespace and cr/lf */ 249 | static const char *skip(const char *in) {while (in && *in && (unsigned char)*in<=32) in++; return in;} 250 | 251 | /* Parse an object - create a new root, and populate. */ 252 | cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int require_null_terminated) 253 | { 254 | const char *end=0; 255 | cJSON *c=cJSON_New_Item(); 256 | ep=0; 257 | if (!c) return 0; /* memory fail */ 258 | 259 | end=parse_value(c,skip(value)); 260 | if (!end) {cJSON_Delete(c);return 0;} /* parse failure. ep is set. */ 261 | 262 | /* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */ 263 | if (require_null_terminated) {end=skip(end);if (*end) {cJSON_Delete(c);ep=end;return 0;}} 264 | if (return_parse_end) *return_parse_end=end; 265 | return c; 266 | } 267 | /* Default options for cJSON_Parse */ 268 | cJSON *cJSON_Parse(const char *value) {return cJSON_ParseWithOpts(value,0,0);} 269 | 270 | /* Render a cJSON item/entity/structure to text. */ 271 | char *cJSON_Print(cJSON *item) {return print_value(item,0,1);} 272 | char *cJSON_PrintUnformatted(cJSON *item) {return print_value(item,0,0);} 273 | 274 | /* Parser core - when encountering text, process appropriately. */ 275 | static const char *parse_value(cJSON *item,const char *value) 276 | { 277 | if (!value) return 0; /* Fail on null. */ 278 | if (!strncmp(value,"null",4)) { item->type=cJSON_NULL; return value+4; } 279 | if (!strncmp(value,"false",5)) { item->type=cJSON_False; return value+5; } 280 | if (!strncmp(value,"true",4)) { item->type=cJSON_True; item->valueint=1; return value+4; } 281 | if (*value=='\"') { return parse_string(item,value); } 282 | if (*value=='-' || (*value>='0' && *value<='9')) { return parse_number(item,value); } 283 | if (*value=='[') { return parse_array(item,value); } 284 | if (*value=='{') { return parse_object(item,value); } 285 | 286 | ep=value;return 0; /* failure. */ 287 | } 288 | 289 | /* Render a value to text. */ 290 | static char *print_value(cJSON *item,int depth,int fmt) 291 | { 292 | char *out=0; 293 | if (!item) return 0; 294 | switch ((item->type)&255) 295 | { 296 | case cJSON_NULL: out=cJSON_strdup("null"); break; 297 | case cJSON_False: out=cJSON_strdup("false");break; 298 | case cJSON_True: out=cJSON_strdup("true"); break; 299 | case cJSON_Number: out=print_number(item);break; 300 | case cJSON_String: out=print_string(item);break; 301 | case cJSON_Array: out=print_array(item,depth,fmt);break; 302 | case cJSON_Object: out=print_object(item,depth,fmt);break; 303 | } 304 | return out; 305 | } 306 | 307 | /* Build an array from input text. */ 308 | static const char *parse_array(cJSON *item,const char *value) 309 | { 310 | cJSON *child; 311 | if (*value!='[') {ep=value;return 0;} /* not an array! */ 312 | 313 | item->type=cJSON_Array; 314 | value=skip(value+1); 315 | if (*value==']') return value+1; /* empty array. */ 316 | 317 | item->child=child=cJSON_New_Item(); 318 | if (!item->child) return 0; /* memory fail */ 319 | value=skip(parse_value(child,skip(value))); /* skip any spacing, get the value. */ 320 | if (!value) return 0; 321 | 322 | while (*value==',') 323 | { 324 | cJSON *new_item; 325 | if (!(new_item=cJSON_New_Item())) return 0; /* memory fail */ 326 | child->next=new_item;new_item->prev=child;child=new_item; 327 | value=skip(parse_value(child,skip(value+1))); 328 | if (!value) return 0; /* memory fail */ 329 | } 330 | 331 | if (*value==']') return value+1; /* end of array */ 332 | ep=value;return 0; /* malformed. */ 333 | } 334 | 335 | /* Render an array to text */ 336 | static char *print_array(cJSON *item,int depth,int fmt) 337 | { 338 | char **entries; 339 | char *out=0,*ptr,*ret;int len=5; 340 | cJSON *child=item->child; 341 | int numentries=0,i=0,fail=0; 342 | 343 | /* How many entries in the array? */ 344 | while (child) numentries++,child=child->next; 345 | /* Explicitly handle numentries==0 */ 346 | if (!numentries) 347 | { 348 | out=(char*)cJSON_malloc(3); 349 | if (out) strcpy(out,"[]"); 350 | return out; 351 | } 352 | /* Allocate an array to hold the values for each */ 353 | entries=(char**)cJSON_malloc(numentries*sizeof(char*)); 354 | if (!entries) return 0; 355 | memset(entries,0,numentries*sizeof(char*)); 356 | /* Retrieve all the results: */ 357 | child=item->child; 358 | while (child && !fail) 359 | { 360 | ret=print_value(child,depth+1,fmt); 361 | entries[i++]=ret; 362 | if (ret) len+=strlen(ret)+2+(fmt?1:0); else fail=1; 363 | child=child->next; 364 | } 365 | 366 | /* If we didn't fail, try to malloc the output string */ 367 | if (!fail) out=(char*)cJSON_malloc(len); 368 | /* If that fails, we fail. */ 369 | if (!out) fail=1; 370 | 371 | /* Handle failure. */ 372 | if (fail) 373 | { 374 | for (i=0;itype=cJSON_Object; 400 | value=skip(value+1); 401 | if (*value=='}') return value+1; /* empty array. */ 402 | 403 | item->child=child=cJSON_New_Item(); 404 | if (!item->child) return 0; 405 | value=skip(parse_string(child,skip(value))); 406 | if (!value) return 0; 407 | child->string=child->valuestring;child->valuestring=0; 408 | if (*value!=':') {ep=value;return 0;} /* fail! */ 409 | value=skip(parse_value(child,skip(value+1))); /* skip any spacing, get the value. */ 410 | if (!value) return 0; 411 | 412 | while (*value==',') 413 | { 414 | cJSON *new_item; 415 | if (!(new_item=cJSON_New_Item())) return 0; /* memory fail */ 416 | child->next=new_item;new_item->prev=child;child=new_item; 417 | value=skip(parse_string(child,skip(value+1))); 418 | if (!value) return 0; 419 | child->string=child->valuestring;child->valuestring=0; 420 | if (*value!=':') {ep=value;return 0;} /* fail! */ 421 | value=skip(parse_value(child,skip(value+1))); /* skip any spacing, get the value. */ 422 | if (!value) return 0; 423 | } 424 | 425 | if (*value=='}') return value+1; /* end of array */ 426 | ep=value;return 0; /* malformed. */ 427 | } 428 | 429 | /* Render an object to text. */ 430 | static char *print_object(cJSON *item,int depth,int fmt) 431 | { 432 | char **entries=0,**names=0; 433 | char *out=0,*ptr,*ret,*str;int len=7,i=0,j; 434 | cJSON *child=item->child; 435 | int numentries=0,fail=0; 436 | /* Count the number of entries. */ 437 | while (child) numentries++,child=child->next; 438 | /* Explicitly handle empty object case */ 439 | if (!numentries) 440 | { 441 | out=(char*)cJSON_malloc(fmt?depth+3:3); 442 | if (!out) return 0; 443 | ptr=out;*ptr++='{'; 444 | if (fmt) {*ptr++='\n';for (i=0;ichild;depth++;if (fmt) len+=depth; 458 | while (child) 459 | { 460 | names[i]=str=print_string_ptr(child->string); 461 | entries[i++]=ret=print_value(child,depth,fmt); 462 | if (str && ret) len+=strlen(ret)+strlen(str)+2+(fmt?2+depth:0); else fail=1; 463 | child=child->next; 464 | } 465 | 466 | /* Try to allocate the output string */ 467 | if (!fail) out=(char*)cJSON_malloc(len); 468 | if (!out) fail=1; 469 | 470 | /* Handle failure */ 471 | if (fail) 472 | { 473 | for (i=0;ichild;int i=0;while(c)i++,c=c->next;return i;} 499 | cJSON *cJSON_GetArrayItem(cJSON *array,int item) {cJSON *c=array->child; while (c && item>0) item--,c=c->next; return c;} 500 | cJSON *cJSON_GetObjectItem(cJSON *object,const char *string) {cJSON *c=object->child; while (c && cJSON_strcasecmp(c->string,string)) c=c->next; return c;} 501 | 502 | /* Utility for array list handling. */ 503 | static void suffix_object(cJSON *prev,cJSON *item) {prev->next=item;item->prev=prev;} 504 | /* Utility for handling references. */ 505 | static cJSON *create_reference(cJSON *item) {cJSON *ref=cJSON_New_Item();if (!ref) return 0;memcpy(ref,item,sizeof(cJSON));ref->string=0;ref->type|=cJSON_IsReference;ref->next=ref->prev=0;return ref;} 506 | 507 | /* Add item to array/object. */ 508 | void cJSON_AddItemToArray(cJSON *array, cJSON *item) {cJSON *c=array->child;if (!item) return; if (!c) {array->child=item;} else {while (c && c->next) c=c->next; suffix_object(c,item);}} 509 | void cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item) {if (!item) return; if (item->string) cJSON_free(item->string);item->string=cJSON_strdup(string);cJSON_AddItemToArray(object,item);} 510 | void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) {cJSON_AddItemToArray(array,create_reference(item));} 511 | void cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item) {cJSON_AddItemToObject(object,string,create_reference(item));} 512 | 513 | cJSON *cJSON_DetachItemFromArray(cJSON *array,int which) {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return 0; 514 | if (c->prev) c->prev->next=c->next;if (c->next) c->next->prev=c->prev;if (c==array->child) array->child=c->next;c->prev=c->next=0;return c;} 515 | void cJSON_DeleteItemFromArray(cJSON *array,int which) {cJSON_Delete(cJSON_DetachItemFromArray(array,which));} 516 | cJSON *cJSON_DetachItemFromObject(cJSON *object,const char *string) {int i=0;cJSON *c=object->child;while (c && cJSON_strcasecmp(c->string,string)) i++,c=c->next;if (c) return cJSON_DetachItemFromArray(object,i);return 0;} 517 | void cJSON_DeleteItemFromObject(cJSON *object,const char *string) {cJSON_Delete(cJSON_DetachItemFromObject(object,string));} 518 | 519 | /* Replace array/object items with new ones. */ 520 | void cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem) {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return; 521 | newitem->next=c->next;newitem->prev=c->prev;if (newitem->next) newitem->next->prev=newitem; 522 | if (c==array->child) array->child=newitem; else newitem->prev->next=newitem;c->next=c->prev=0;cJSON_Delete(c);} 523 | void cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem){int i=0;cJSON *c=object->child;while(c && cJSON_strcasecmp(c->string,string))i++,c=c->next;if(c){newitem->string=cJSON_strdup(string);cJSON_ReplaceItemInArray(object,i,newitem);}} 524 | 525 | /* Create basic types: */ 526 | cJSON *cJSON_CreateNull(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_NULL;return item;} 527 | cJSON *cJSON_CreateTrue(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_True;return item;} 528 | cJSON *cJSON_CreateFalse(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_False;return item;} 529 | cJSON *cJSON_CreateBool(int b) {cJSON *item=cJSON_New_Item();if(item)item->type=b?cJSON_True:cJSON_False;return item;} 530 | cJSON *cJSON_CreateNumber(double num) {cJSON *item=cJSON_New_Item();if(item){item->type=cJSON_Number;item->valuedouble=num;item->valueint=(int)num;}return item;} 531 | cJSON *cJSON_CreateString(const char *string) {cJSON *item=cJSON_New_Item();if(item){item->type=cJSON_String;item->valuestring=cJSON_strdup(string);}return item;} 532 | cJSON *cJSON_CreateArray(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Array;return item;} 533 | cJSON *cJSON_CreateObject(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Object;return item;} 534 | 535 | /* Create Arrays: */ 536 | cJSON *cJSON_CreateIntArray(int *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && ichild=n;else suffix_object(p,n);p=n;}return a;} 537 | cJSON *cJSON_CreateFloatArray(float *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && ichild=n;else suffix_object(p,n);p=n;}return a;} 538 | cJSON *cJSON_CreateDoubleArray(double *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && ichild=n;else suffix_object(p,n);p=n;}return a;} 539 | cJSON *cJSON_CreateStringArray(const char **strings,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && ichild=n;else suffix_object(p,n);p=n;}return a;} 540 | 541 | /* Duplication */ 542 | cJSON *cJSON_Duplicate(cJSON *item,int recurse) 543 | { 544 | cJSON *newitem,*cptr,*nptr=0,*newchild; 545 | /* Bail on bad ptr */ 546 | if (!item) return 0; 547 | /* Create new item */ 548 | newitem=cJSON_New_Item(); 549 | if (!newitem) return 0; 550 | /* Copy over all vars */ 551 | newitem->type=item->type&(~cJSON_IsReference),newitem->valueint=item->valueint,newitem->valuedouble=item->valuedouble; 552 | if (item->valuestring) {newitem->valuestring=cJSON_strdup(item->valuestring); if (!newitem->valuestring) {cJSON_Delete(newitem);return 0;}} 553 | if (item->string) {newitem->string=cJSON_strdup(item->string); if (!newitem->string) {cJSON_Delete(newitem);return 0;}} 554 | /* If non-recursive, then we're done! */ 555 | if (!recurse) return newitem; 556 | /* Walk the ->next chain for the child. */ 557 | cptr=item->child; 558 | while (cptr) 559 | { 560 | newchild=cJSON_Duplicate(cptr,1); /* Duplicate (with recurse) each item in the ->next chain */ 561 | if (!newchild) {cJSON_Delete(newitem);return 0;} 562 | if (nptr) {nptr->next=newchild,newchild->prev=nptr;nptr=newchild;} /* If newitem->child already set, then crosswire ->prev and ->next and move on */ 563 | else {newitem->child=newchild;nptr=newchild;} /* Set newitem->child and move to it */ 564 | cptr=cptr->next; 565 | } 566 | return newitem; 567 | } 568 | -------------------------------------------------------------------------------- /src/ngx_http_parser.c: -------------------------------------------------------------------------------- 1 | /* Based on src/http/ngx_http_parse.c from NGINX copyright Igor Sysoev 2 | * 3 | * Additional changes are licensed under the same terms as NGINX and 4 | * copyright Joyent, Inc. and other Node contributors. All rights reserved. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to 8 | * deal in the Software without restriction, including without limitation the 9 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 10 | * sell copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 22 | * IN THE SOFTWARE. 23 | */ 24 | #include "ngx_http_parser.h" 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | #ifndef ULLONG_MAX 33 | # define ULLONG_MAX ((uint64_t) -1) /* 2^64-1 */ 34 | #endif 35 | 36 | #ifndef MIN 37 | # define MIN(a,b) ((a) < (b) ? (a) : (b)) 38 | #endif 39 | 40 | #ifndef ARRAY_SIZE 41 | # define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) 42 | #endif 43 | 44 | #ifndef BIT_AT 45 | # define BIT_AT(a, i) \ 46 | (!!((unsigned int) (a)[(unsigned int) (i) >> 3] & \ 47 | (1 << ((unsigned int) (i) & 7)))) 48 | #endif 49 | 50 | #ifndef ELEM_AT 51 | # define ELEM_AT(a, i, v) ((unsigned int) (i) < ARRAY_SIZE(a) ? (a)[(i)] : (v)) 52 | #endif 53 | 54 | #define SET_ERRNO(e) \ 55 | do { \ 56 | parser->http_errno = (e); \ 57 | } while(0) 58 | 59 | #define CURRENT_STATE() p_state 60 | #define UPDATE_STATE(V) p_state = (enum state) (V); 61 | #define RETURN(V) \ 62 | do { \ 63 | parser->state = CURRENT_STATE(); \ 64 | return (V); \ 65 | } while (0); 66 | #define REEXECUTE() \ 67 | goto reexecute; \ 68 | 69 | 70 | #ifdef __GNUC__ 71 | # define LIKELY(X) __builtin_expect(!!(X), 1) 72 | # define UNLIKELY(X) __builtin_expect(!!(X), 0) 73 | #else 74 | # define LIKELY(X) (X) 75 | # define UNLIKELY(X) (X) 76 | #endif 77 | 78 | 79 | /* Run the notify callback FOR, returning ER if it fails */ 80 | #define CALLBACK_NOTIFY_(FOR, ER) \ 81 | do { \ 82 | assert(HTTP_PARSER_ERRNO(parser) == HPE_OK); \ 83 | \ 84 | if (LIKELY(settings->on_##FOR)) { \ 85 | parser->state = CURRENT_STATE(); \ 86 | if (UNLIKELY(0 != settings->on_##FOR(parser))) { \ 87 | SET_ERRNO(HPE_CB_##FOR); \ 88 | } \ 89 | UPDATE_STATE(parser->state); \ 90 | \ 91 | /* We either errored above or got paused; get out */ \ 92 | if (UNLIKELY(HTTP_PARSER_ERRNO(parser) != HPE_OK)) { \ 93 | return (ER); \ 94 | } \ 95 | } \ 96 | } while (0) 97 | 98 | /* Run the notify callback FOR and consume the current byte */ 99 | #define CALLBACK_NOTIFY(FOR) CALLBACK_NOTIFY_(FOR, p - data + 1) 100 | 101 | /* Run the notify callback FOR and don't consume the current byte */ 102 | #define CALLBACK_NOTIFY_NOADVANCE(FOR) CALLBACK_NOTIFY_(FOR, p - data) 103 | 104 | /* Run data callback FOR with LEN bytes, returning ER if it fails */ 105 | #define CALLBACK_DATA_(FOR, LEN, ER) \ 106 | do { \ 107 | assert(HTTP_PARSER_ERRNO(parser) == HPE_OK); \ 108 | \ 109 | if (FOR##_mark) { \ 110 | if (LIKELY(settings->on_##FOR)) { \ 111 | parser->state = CURRENT_STATE(); \ 112 | if (UNLIKELY(0 != \ 113 | settings->on_##FOR(parser, FOR##_mark, (LEN)))) { \ 114 | SET_ERRNO(HPE_CB_##FOR); \ 115 | } \ 116 | UPDATE_STATE(parser->state); \ 117 | \ 118 | /* We either errored above or got paused; get out */ \ 119 | if (UNLIKELY(HTTP_PARSER_ERRNO(parser) != HPE_OK)) { \ 120 | return (ER); \ 121 | } \ 122 | } \ 123 | FOR##_mark = NULL; \ 124 | } \ 125 | } while (0) 126 | 127 | /* Run the data callback FOR and consume the current byte */ 128 | #define CALLBACK_DATA(FOR) \ 129 | CALLBACK_DATA_(FOR, p - FOR##_mark, p - data + 1) 130 | 131 | /* Run the data callback FOR and don't consume the current byte */ 132 | #define CALLBACK_DATA_NOADVANCE(FOR) \ 133 | CALLBACK_DATA_(FOR, p - FOR##_mark, p - data) 134 | 135 | /* Set the mark FOR; non-destructive if mark is already set */ 136 | #define MARK(FOR) \ 137 | do { \ 138 | if (!FOR##_mark) { \ 139 | FOR##_mark = p; \ 140 | } \ 141 | } while (0) 142 | 143 | /* Don't allow the total size of the HTTP headers (including the status 144 | * line) to exceed HTTP_MAX_HEADER_SIZE. This check is here to protect 145 | * embedders against denial-of-service attacks where the attacker feeds 146 | * us a never-ending header that the embedder keeps buffering. 147 | * 148 | * This check is arguably the responsibility of embedders but we're doing 149 | * it on the embedder's behalf because most won't bother and this way we 150 | * make the web a little safer. HTTP_MAX_HEADER_SIZE is still far bigger 151 | * than any reasonable request or response so this should never affect 152 | * day-to-day operation. 153 | */ 154 | #define COUNT_HEADER_SIZE(V) \ 155 | do { \ 156 | parser->nread += (V); \ 157 | if (UNLIKELY(parser->nread > (HTTP_MAX_HEADER_SIZE))) { \ 158 | SET_ERRNO(HPE_HEADER_OVERFLOW); \ 159 | goto error; \ 160 | } \ 161 | } while (0) 162 | 163 | 164 | #define PROXY_CONNECTION "proxy-connection" 165 | #define CONNECTION "connection" 166 | #define CONTENT_LENGTH "content-length" 167 | #define TRANSFER_ENCODING "transfer-encoding" 168 | #define UPGRADE "upgrade" 169 | #define CHUNKED "chunked" 170 | #define KEEP_ALIVE "keep-alive" 171 | #define CLOSE "close" 172 | 173 | 174 | static const char *method_strings[] = 175 | { 176 | #define XX(num, name, string) #string, 177 | HTTP_METHOD_MAP(XX) 178 | #undef XX 179 | }; 180 | 181 | 182 | /* Tokens as defined by rfc 2616. Also lowercases them. 183 | * token = 1* 184 | * separators = "(" | ")" | "<" | ">" | "@" 185 | * | "," | ";" | ":" | "\" | <"> 186 | * | "/" | "[" | "]" | "?" | "=" 187 | * | "{" | "}" | SP | HT 188 | */ 189 | static const char tokens[256] = { 190 | /* 0 nul 1 soh 2 stx 3 etx 4 eot 5 enq 6 ack 7 bel */ 191 | 0, 0, 0, 0, 0, 0, 0, 0, 192 | /* 8 bs 9 ht 10 nl 11 vt 12 np 13 cr 14 so 15 si */ 193 | 0, 0, 0, 0, 0, 0, 0, 0, 194 | /* 16 dle 17 dc1 18 dc2 19 dc3 20 dc4 21 nak 22 syn 23 etb */ 195 | 0, 0, 0, 0, 0, 0, 0, 0, 196 | /* 24 can 25 em 26 sub 27 esc 28 fs 29 gs 30 rs 31 us */ 197 | 0, 0, 0, 0, 0, 0, 0, 0, 198 | /* 32 sp 33 ! 34 " 35 # 36 $ 37 % 38 & 39 ' */ 199 | 0, '!', 0, '#', '$', '%', '&', '\'', 200 | /* 40 ( 41 ) 42 * 43 + 44 , 45 - 46 . 47 / */ 201 | 0, 0, '*', '+', 0, '-', '.', 0, 202 | /* 48 0 49 1 50 2 51 3 52 4 53 5 54 6 55 7 */ 203 | '0', '1', '2', '3', '4', '5', '6', '7', 204 | /* 56 8 57 9 58 : 59 ; 60 < 61 = 62 > 63 ? */ 205 | '8', '9', 0, 0, 0, 0, 0, 0, 206 | /* 64 @ 65 A 66 B 67 C 68 D 69 E 70 F 71 G */ 207 | 0, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 208 | /* 72 H 73 I 74 J 75 K 76 L 77 M 78 N 79 O */ 209 | 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 210 | /* 80 P 81 Q 82 R 83 S 84 T 85 U 86 V 87 W */ 211 | 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 212 | /* 88 X 89 Y 90 Z 91 [ 92 \ 93 ] 94 ^ 95 _ */ 213 | 'x', 'y', 'z', 0, 0, 0, '^', '_', 214 | /* 96 ` 97 a 98 b 99 c 100 d 101 e 102 f 103 g */ 215 | '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 216 | /* 104 h 105 i 106 j 107 k 108 l 109 m 110 n 111 o */ 217 | 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 218 | /* 112 p 113 q 114 r 115 s 116 t 117 u 118 v 119 w */ 219 | 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 220 | /* 120 x 121 y 122 z 123 { 124 | 125 } 126 ~ 127 del */ 221 | 'x', 'y', 'z', 0, '|', 0, '~', 0 }; 222 | 223 | 224 | static const int8_t unhex[256] = 225 | {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 226 | ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 227 | ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 228 | , 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1 229 | ,-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1 230 | ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 231 | ,-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1 232 | ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 233 | }; 234 | 235 | 236 | #if HTTP_PARSER_STRICT 237 | # define T(v) 0 238 | #else 239 | # define T(v) v 240 | #endif 241 | 242 | 243 | static const uint8_t normal_url_char[32] = { 244 | /* 0 nul 1 soh 2 stx 3 etx 4 eot 5 enq 6 ack 7 bel */ 245 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0, 246 | /* 8 bs 9 ht 10 nl 11 vt 12 np 13 cr 14 so 15 si */ 247 | 0 | T(2) | 0 | 0 | T(16) | 0 | 0 | 0, 248 | /* 16 dle 17 dc1 18 dc2 19 dc3 20 dc4 21 nak 22 syn 23 etb */ 249 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0, 250 | /* 24 can 25 em 26 sub 27 esc 28 fs 29 gs 30 rs 31 us */ 251 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0, 252 | /* 32 sp 33 ! 34 " 35 # 36 $ 37 % 38 & 39 ' */ 253 | 0 | 2 | 4 | 0 | 16 | 32 | 64 | 128, 254 | /* 40 ( 41 ) 42 * 43 + 44 , 45 - 46 . 47 / */ 255 | 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, 256 | /* 48 0 49 1 50 2 51 3 52 4 53 5 54 6 55 7 */ 257 | 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, 258 | /* 56 8 57 9 58 : 59 ; 60 < 61 = 62 > 63 ? */ 259 | 1 | 2 | 4 | 8 | 16 | 32 | 64 | 0, 260 | /* 64 @ 65 A 66 B 67 C 68 D 69 E 70 F 71 G */ 261 | 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, 262 | /* 72 H 73 I 74 J 75 K 76 L 77 M 78 N 79 O */ 263 | 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, 264 | /* 80 P 81 Q 82 R 83 S 84 T 85 U 86 V 87 W */ 265 | 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, 266 | /* 88 X 89 Y 90 Z 91 [ 92 \ 93 ] 94 ^ 95 _ */ 267 | 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, 268 | /* 96 ` 97 a 98 b 99 c 100 d 101 e 102 f 103 g */ 269 | 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, 270 | /* 104 h 105 i 106 j 107 k 108 l 109 m 110 n 111 o */ 271 | 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, 272 | /* 112 p 113 q 114 r 115 s 116 t 117 u 118 v 119 w */ 273 | 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, 274 | /* 120 x 121 y 122 z 123 { 124 | 125 } 126 ~ 127 del */ 275 | 1 | 2 | 4 | 8 | 16 | 32 | 64 | 0, }; 276 | 277 | #undef T 278 | 279 | enum state 280 | { s_dead = 1 /* important that this is > 0 */ 281 | 282 | , s_start_req_or_res 283 | , s_res_or_resp_H 284 | , s_start_res 285 | , s_res_H 286 | , s_res_HT 287 | , s_res_HTT 288 | , s_res_HTTP 289 | , s_res_first_http_major 290 | , s_res_http_major 291 | , s_res_first_http_minor 292 | , s_res_http_minor 293 | , s_res_first_status_code 294 | , s_res_status_code 295 | , s_res_status_start 296 | , s_res_status 297 | , s_res_line_almost_done 298 | 299 | , s_start_req 300 | 301 | , s_req_method 302 | , s_req_spaces_before_url 303 | , s_req_schema 304 | , s_req_schema_slash 305 | , s_req_schema_slash_slash 306 | , s_req_server_start 307 | , s_req_server 308 | , s_req_server_with_at 309 | , s_req_path 310 | , s_req_query_string_start 311 | , s_req_query_string 312 | , s_req_fragment_start 313 | , s_req_fragment 314 | , s_req_http_start 315 | , s_req_http_H 316 | , s_req_http_HT 317 | , s_req_http_HTT 318 | , s_req_http_HTTP 319 | , s_req_first_http_major 320 | , s_req_http_major 321 | , s_req_first_http_minor 322 | , s_req_http_minor 323 | , s_req_line_almost_done 324 | 325 | , s_header_field_start 326 | , s_header_field 327 | , s_header_value_discard_ws 328 | , s_header_value_discard_ws_almost_done 329 | , s_header_value_discard_lws 330 | , s_header_value_start 331 | , s_header_value 332 | , s_header_value_lws 333 | 334 | , s_header_almost_done 335 | 336 | , s_chunk_size_start 337 | , s_chunk_size 338 | , s_chunk_parameters 339 | , s_chunk_size_almost_done 340 | 341 | , s_headers_almost_done 342 | , s_headers_done 343 | 344 | /* Important: 's_headers_done' must be the last 'header' state. All 345 | * states beyond this must be 'body' states. It is used for overflow 346 | * checking. See the PARSING_HEADER() macro. 347 | */ 348 | 349 | , s_chunk_data 350 | , s_chunk_data_almost_done 351 | , s_chunk_data_done 352 | 353 | , s_body_identity 354 | , s_body_identity_eof 355 | 356 | , s_message_done 357 | }; 358 | 359 | 360 | #define PARSING_HEADER(state) (state <= s_headers_done) 361 | 362 | 363 | enum header_states 364 | { h_general = 0 365 | , h_C 366 | , h_CO 367 | , h_CON 368 | 369 | , h_matching_connection 370 | , h_matching_proxy_connection 371 | , h_matching_content_length 372 | , h_matching_transfer_encoding 373 | , h_matching_upgrade 374 | 375 | , h_connection 376 | , h_content_length 377 | , h_transfer_encoding 378 | , h_upgrade 379 | 380 | , h_matching_transfer_encoding_chunked 381 | , h_matching_connection_token_start 382 | , h_matching_connection_keep_alive 383 | , h_matching_connection_close 384 | , h_matching_connection_upgrade 385 | , h_matching_connection_token 386 | 387 | , h_transfer_encoding_chunked 388 | , h_connection_keep_alive 389 | , h_connection_close 390 | , h_connection_upgrade 391 | }; 392 | 393 | enum http_host_state 394 | { 395 | s_http_host_dead = 1 396 | , s_http_userinfo_start 397 | , s_http_userinfo 398 | , s_http_host_start 399 | , s_http_host_v6_start 400 | , s_http_host 401 | , s_http_host_v6 402 | , s_http_host_v6_end 403 | , s_http_host_port_start 404 | , s_http_host_port 405 | }; 406 | 407 | /* Macros for character classes; depends on strict-mode */ 408 | #define CR '\r' 409 | #define LF '\n' 410 | #define LOWER(c) (unsigned char)(c | 0x20) 411 | #define IS_ALPHA(c) (LOWER(c) >= 'a' && LOWER(c) <= 'z') 412 | #define IS_NUM(c) ((c) >= '0' && (c) <= '9') 413 | #define IS_ALPHANUM(c) (IS_ALPHA(c) || IS_NUM(c)) 414 | #define IS_HEX(c) (IS_NUM(c) || (LOWER(c) >= 'a' && LOWER(c) <= 'f')) 415 | #define IS_MARK(c) ((c) == '-' || (c) == '_' || (c) == '.' || \ 416 | (c) == '!' || (c) == '~' || (c) == '*' || (c) == '\'' || (c) == '(' || \ 417 | (c) == ')') 418 | #define IS_USERINFO_CHAR(c) (IS_ALPHANUM(c) || IS_MARK(c) || (c) == '%' || \ 419 | (c) == ';' || (c) == ':' || (c) == '&' || (c) == '=' || (c) == '+' || \ 420 | (c) == '$' || (c) == ',') 421 | 422 | #define STRICT_TOKEN(c) (tokens[(unsigned char)c]) 423 | 424 | #if HTTP_PARSER_STRICT 425 | #define TOKEN(c) (tokens[(unsigned char)c]) 426 | #define IS_URL_CHAR(c) (BIT_AT(normal_url_char, (unsigned char)c)) 427 | #define IS_HOST_CHAR(c) (IS_ALPHANUM(c) || (c) == '.' || (c) == '-') 428 | #else 429 | #define TOKEN(c) ((c == ' ') ? ' ' : tokens[(unsigned char)c]) 430 | #define IS_URL_CHAR(c) \ 431 | (BIT_AT(normal_url_char, (unsigned char)c) || ((c) & 0x80)) 432 | #define IS_HOST_CHAR(c) \ 433 | (IS_ALPHANUM(c) || (c) == '.' || (c) == '-' || (c) == '_') 434 | #endif 435 | 436 | 437 | #define start_state (parser->type == HTTP_REQUEST ? s_start_req : s_start_res) 438 | 439 | 440 | #if HTTP_PARSER_STRICT 441 | # define STRICT_CHECK(cond) \ 442 | do { \ 443 | if (cond) { \ 444 | SET_ERRNO(HPE_STRICT); \ 445 | goto error; \ 446 | } \ 447 | } while (0) 448 | # define NEW_MESSAGE() (http_should_keep_alive(parser) ? start_state : s_dead) 449 | #else 450 | # define STRICT_CHECK(cond) 451 | # define NEW_MESSAGE() start_state 452 | #endif 453 | 454 | 455 | /* Map errno values to strings for human-readable output */ 456 | #define HTTP_STRERROR_GEN(n, s) { "HPE_" #n, s }, 457 | static struct { 458 | const char *name; 459 | const char *description; 460 | } http_strerror_tab[] = { 461 | HTTP_ERRNO_MAP(HTTP_STRERROR_GEN) 462 | }; 463 | #undef HTTP_STRERROR_GEN 464 | 465 | int http_message_needs_eof(const http_parser *parser); 466 | 467 | /* Our URL parser. 468 | * 469 | * This is designed to be shared by http_parser_execute() for URL validation, 470 | * hence it has a state transition + byte-for-byte interface. In addition, it 471 | * is meant to be embedded in http_parser_parse_url(), which does the dirty 472 | * work of turning state transitions URL components for its API. 473 | * 474 | * This function should only be invoked with non-space characters. It is 475 | * assumed that the caller cares about (and can detect) the transition between 476 | * URL and non-URL states by looking for these. 477 | */ 478 | static enum state 479 | parse_url_char(enum state s, const char ch) 480 | { 481 | if (ch == ' ' || ch == '\r' || ch == '\n') { 482 | return s_dead; 483 | } 484 | 485 | #if HTTP_PARSER_STRICT 486 | if (ch == '\t' || ch == '\f') { 487 | return s_dead; 488 | } 489 | #endif 490 | 491 | switch (s) { 492 | case s_req_spaces_before_url: 493 | /* Proxied requests are followed by scheme of an absolute URI (alpha). 494 | * All methods except CONNECT are followed by '/' or '*'. 495 | */ 496 | 497 | if (ch == '/' || ch == '*') { 498 | return s_req_path; 499 | } 500 | 501 | if (IS_ALPHA(ch)) { 502 | return s_req_schema; 503 | } 504 | 505 | break; 506 | 507 | case s_req_schema: 508 | if (IS_ALPHA(ch)) { 509 | return s; 510 | } 511 | 512 | if (ch == ':') { 513 | return s_req_schema_slash; 514 | } 515 | 516 | break; 517 | 518 | case s_req_schema_slash: 519 | if (ch == '/') { 520 | return s_req_schema_slash_slash; 521 | } 522 | 523 | break; 524 | 525 | case s_req_schema_slash_slash: 526 | if (ch == '/') { 527 | return s_req_server_start; 528 | } 529 | 530 | break; 531 | 532 | case s_req_server_with_at: 533 | if (ch == '@') { 534 | return s_dead; 535 | } 536 | 537 | /* FALLTHROUGH */ 538 | case s_req_server_start: 539 | case s_req_server: 540 | if (ch == '/') { 541 | return s_req_path; 542 | } 543 | 544 | if (ch == '?') { 545 | return s_req_query_string_start; 546 | } 547 | 548 | if (ch == '@') { 549 | return s_req_server_with_at; 550 | } 551 | 552 | if (IS_USERINFO_CHAR(ch) || ch == '[' || ch == ']') { 553 | return s_req_server; 554 | } 555 | 556 | break; 557 | 558 | case s_req_path: 559 | if (IS_URL_CHAR(ch)) { 560 | return s; 561 | } 562 | 563 | switch (ch) { 564 | case '?': 565 | return s_req_query_string_start; 566 | 567 | case '#': 568 | return s_req_fragment_start; 569 | } 570 | 571 | break; 572 | 573 | case s_req_query_string_start: 574 | case s_req_query_string: 575 | if (IS_URL_CHAR(ch)) { 576 | return s_req_query_string; 577 | } 578 | 579 | switch (ch) { 580 | case '?': 581 | /* allow extra '?' in query string */ 582 | return s_req_query_string; 583 | 584 | case '#': 585 | return s_req_fragment_start; 586 | } 587 | 588 | break; 589 | 590 | case s_req_fragment_start: 591 | if (IS_URL_CHAR(ch)) { 592 | return s_req_fragment; 593 | } 594 | 595 | switch (ch) { 596 | case '?': 597 | return s_req_fragment; 598 | 599 | case '#': 600 | return s; 601 | } 602 | 603 | break; 604 | 605 | case s_req_fragment: 606 | if (IS_URL_CHAR(ch)) { 607 | return s; 608 | } 609 | 610 | switch (ch) { 611 | case '?': 612 | case '#': 613 | return s; 614 | } 615 | 616 | break; 617 | 618 | default: 619 | break; 620 | } 621 | 622 | /* We should never fall out of the switch above unless there's an error */ 623 | return s_dead; 624 | } 625 | 626 | size_t http_parser_execute (http_parser *parser, 627 | const http_parser_settings *settings, 628 | const char *data, 629 | size_t len) 630 | { 631 | char c, ch; 632 | int8_t unhex_val; 633 | const char *p = data; 634 | const char *header_field_mark = 0; 635 | const char *header_value_mark = 0; 636 | const char *url_mark = 0; 637 | const char *body_mark = 0; 638 | const char *status_mark = 0; 639 | enum state p_state = (enum state) parser->state; 640 | 641 | /* We're in an error state. Don't bother doing anything. */ 642 | if (HTTP_PARSER_ERRNO(parser) != HPE_OK) { 643 | return 0; 644 | } 645 | 646 | if (len == 0) { 647 | switch (CURRENT_STATE()) { 648 | case s_body_identity_eof: 649 | /* Use of CALLBACK_NOTIFY() here would erroneously return 1 byte read if 650 | * we got paused. 651 | */ 652 | CALLBACK_NOTIFY_NOADVANCE(message_complete); 653 | return 0; 654 | 655 | case s_dead: 656 | case s_start_req_or_res: 657 | case s_start_res: 658 | case s_start_req: 659 | return 0; 660 | 661 | default: 662 | SET_ERRNO(HPE_INVALID_EOF_STATE); 663 | return 1; 664 | } 665 | } 666 | 667 | 668 | if (CURRENT_STATE() == s_header_field) 669 | header_field_mark = data; 670 | if (CURRENT_STATE() == s_header_value) 671 | header_value_mark = data; 672 | switch (CURRENT_STATE()) { 673 | case s_req_path: 674 | case s_req_schema: 675 | case s_req_schema_slash: 676 | case s_req_schema_slash_slash: 677 | case s_req_server_start: 678 | case s_req_server: 679 | case s_req_server_with_at: 680 | case s_req_query_string_start: 681 | case s_req_query_string: 682 | case s_req_fragment_start: 683 | case s_req_fragment: 684 | url_mark = data; 685 | break; 686 | case s_res_status: 687 | status_mark = data; 688 | break; 689 | default: 690 | break; 691 | } 692 | 693 | for (p=data; p != data + len; p++) { 694 | ch = *p; 695 | 696 | if (PARSING_HEADER(CURRENT_STATE())) 697 | COUNT_HEADER_SIZE(1); 698 | 699 | reexecute: 700 | switch (CURRENT_STATE()) { 701 | 702 | case s_dead: 703 | /* this state is used after a 'Connection: close' message 704 | * the parser will error out if it reads another message 705 | */ 706 | if (LIKELY(ch == CR || ch == LF)) 707 | break; 708 | 709 | SET_ERRNO(HPE_CLOSED_CONNECTION); 710 | goto error; 711 | 712 | case s_start_req_or_res: 713 | { 714 | if (ch == CR || ch == LF) 715 | break; 716 | parser->flags = 0; 717 | parser->content_length = ULLONG_MAX; 718 | 719 | if (ch == 'H') { 720 | UPDATE_STATE(s_res_or_resp_H); 721 | 722 | CALLBACK_NOTIFY(message_begin); 723 | } else { 724 | parser->type = HTTP_REQUEST; 725 | UPDATE_STATE(s_start_req); 726 | REEXECUTE(); 727 | } 728 | 729 | break; 730 | } 731 | 732 | case s_res_or_resp_H: 733 | if (ch == 'T') { 734 | parser->type = HTTP_RESPONSE; 735 | UPDATE_STATE(s_res_HT); 736 | } else { 737 | if (UNLIKELY(ch != 'E')) { 738 | SET_ERRNO(HPE_INVALID_CONSTANT); 739 | goto error; 740 | } 741 | 742 | parser->type = HTTP_REQUEST; 743 | parser->method = HTTP_HEAD; 744 | parser->index = 2; 745 | UPDATE_STATE(s_req_method); 746 | } 747 | break; 748 | 749 | case s_start_res: 750 | { 751 | parser->flags = 0; 752 | parser->content_length = ULLONG_MAX; 753 | 754 | switch (ch) { 755 | case 'H': 756 | UPDATE_STATE(s_res_H); 757 | break; 758 | 759 | case CR: 760 | case LF: 761 | break; 762 | 763 | default: 764 | SET_ERRNO(HPE_INVALID_CONSTANT); 765 | goto error; 766 | } 767 | 768 | CALLBACK_NOTIFY(message_begin); 769 | break; 770 | } 771 | 772 | case s_res_H: 773 | STRICT_CHECK(ch != 'T'); 774 | UPDATE_STATE(s_res_HT); 775 | break; 776 | 777 | case s_res_HT: 778 | STRICT_CHECK(ch != 'T'); 779 | UPDATE_STATE(s_res_HTT); 780 | break; 781 | 782 | case s_res_HTT: 783 | STRICT_CHECK(ch != 'P'); 784 | UPDATE_STATE(s_res_HTTP); 785 | break; 786 | 787 | case s_res_HTTP: 788 | STRICT_CHECK(ch != '/'); 789 | UPDATE_STATE(s_res_first_http_major); 790 | break; 791 | 792 | case s_res_first_http_major: 793 | if (UNLIKELY(ch < '0' || ch > '9')) { 794 | SET_ERRNO(HPE_INVALID_VERSION); 795 | goto error; 796 | } 797 | 798 | parser->http_major = ch - '0'; 799 | UPDATE_STATE(s_res_http_major); 800 | break; 801 | 802 | /* major HTTP version or dot */ 803 | case s_res_http_major: 804 | { 805 | if (ch == '.') { 806 | UPDATE_STATE(s_res_first_http_minor); 807 | break; 808 | } 809 | 810 | if (!IS_NUM(ch)) { 811 | SET_ERRNO(HPE_INVALID_VERSION); 812 | goto error; 813 | } 814 | 815 | parser->http_major *= 10; 816 | parser->http_major += ch - '0'; 817 | 818 | if (UNLIKELY(parser->http_major > 999)) { 819 | SET_ERRNO(HPE_INVALID_VERSION); 820 | goto error; 821 | } 822 | 823 | break; 824 | } 825 | 826 | /* first digit of minor HTTP version */ 827 | case s_res_first_http_minor: 828 | if (UNLIKELY(!IS_NUM(ch))) { 829 | SET_ERRNO(HPE_INVALID_VERSION); 830 | goto error; 831 | } 832 | 833 | parser->http_minor = ch - '0'; 834 | UPDATE_STATE(s_res_http_minor); 835 | break; 836 | 837 | /* minor HTTP version or end of request line */ 838 | case s_res_http_minor: 839 | { 840 | if (ch == ' ') { 841 | UPDATE_STATE(s_res_first_status_code); 842 | break; 843 | } 844 | 845 | if (UNLIKELY(!IS_NUM(ch))) { 846 | SET_ERRNO(HPE_INVALID_VERSION); 847 | goto error; 848 | } 849 | 850 | parser->http_minor *= 10; 851 | parser->http_minor += ch - '0'; 852 | 853 | if (UNLIKELY(parser->http_minor > 999)) { 854 | SET_ERRNO(HPE_INVALID_VERSION); 855 | goto error; 856 | } 857 | 858 | break; 859 | } 860 | 861 | case s_res_first_status_code: 862 | { 863 | if (!IS_NUM(ch)) { 864 | if (ch == ' ') { 865 | break; 866 | } 867 | 868 | SET_ERRNO(HPE_INVALID_STATUS); 869 | goto error; 870 | } 871 | parser->status_code = ch - '0'; 872 | UPDATE_STATE(s_res_status_code); 873 | break; 874 | } 875 | 876 | case s_res_status_code: 877 | { 878 | if (!IS_NUM(ch)) { 879 | switch (ch) { 880 | case ' ': 881 | UPDATE_STATE(s_res_status_start); 882 | break; 883 | case CR: 884 | UPDATE_STATE(s_res_line_almost_done); 885 | break; 886 | case LF: 887 | UPDATE_STATE(s_header_field_start); 888 | break; 889 | default: 890 | SET_ERRNO(HPE_INVALID_STATUS); 891 | goto error; 892 | } 893 | break; 894 | } 895 | 896 | parser->status_code *= 10; 897 | parser->status_code += ch - '0'; 898 | 899 | if (UNLIKELY(parser->status_code > 999)) { 900 | SET_ERRNO(HPE_INVALID_STATUS); 901 | goto error; 902 | } 903 | 904 | break; 905 | } 906 | 907 | case s_res_status_start: 908 | { 909 | if (ch == CR) { 910 | UPDATE_STATE(s_res_line_almost_done); 911 | break; 912 | } 913 | 914 | if (ch == LF) { 915 | UPDATE_STATE(s_header_field_start); 916 | break; 917 | } 918 | 919 | MARK(status); 920 | UPDATE_STATE(s_res_status); 921 | parser->index = 0; 922 | break; 923 | } 924 | 925 | case s_res_status: 926 | if (ch == CR) { 927 | UPDATE_STATE(s_res_line_almost_done); 928 | CALLBACK_DATA(status); 929 | break; 930 | } 931 | 932 | if (ch == LF) { 933 | UPDATE_STATE(s_header_field_start); 934 | CALLBACK_DATA(status); 935 | break; 936 | } 937 | 938 | break; 939 | 940 | case s_res_line_almost_done: 941 | STRICT_CHECK(ch != LF); 942 | UPDATE_STATE(s_header_field_start); 943 | break; 944 | 945 | case s_start_req: 946 | { 947 | if (ch == CR || ch == LF) 948 | break; 949 | parser->flags = 0; 950 | parser->content_length = ULLONG_MAX; 951 | 952 | if (UNLIKELY(!IS_ALPHA(ch))) { 953 | SET_ERRNO(HPE_INVALID_METHOD); 954 | goto error; 955 | } 956 | 957 | parser->method = (enum http_method) 0; 958 | parser->index = 1; 959 | switch (ch) { 960 | case 'C': parser->method = HTTP_CONNECT; /* or COPY, CHECKOUT */ break; 961 | case 'D': parser->method = HTTP_DELETE; break; 962 | case 'G': parser->method = HTTP_GET; break; 963 | case 'H': parser->method = HTTP_HEAD; break; 964 | case 'L': parser->method = HTTP_LOCK; break; 965 | case 'M': parser->method = HTTP_MKCOL; /* or MOVE, MKACTIVITY, MERGE, M-SEARCH, MKCALENDAR */ break; 966 | case 'N': parser->method = HTTP_NOTIFY; break; 967 | case 'O': parser->method = HTTP_OPTIONS; break; 968 | case 'P': parser->method = HTTP_POST; 969 | /* or PROPFIND|PROPPATCH|PUT|PATCH|PURGE */ 970 | break; 971 | case 'R': parser->method = HTTP_REPORT; break; 972 | case 'S': parser->method = HTTP_SUBSCRIBE; /* or SEARCH */ break; 973 | case 'T': parser->method = HTTP_TRACE; break; 974 | case 'U': parser->method = HTTP_UNLOCK; /* or UNSUBSCRIBE */ break; 975 | default: 976 | SET_ERRNO(HPE_INVALID_METHOD); 977 | goto error; 978 | } 979 | UPDATE_STATE(s_req_method); 980 | 981 | CALLBACK_NOTIFY(message_begin); 982 | 983 | break; 984 | } 985 | 986 | case s_req_method: 987 | { 988 | const char *matcher; 989 | if (UNLIKELY(ch == '\0')) { 990 | SET_ERRNO(HPE_INVALID_METHOD); 991 | goto error; 992 | } 993 | 994 | matcher = method_strings[parser->method]; 995 | if (ch == ' ' && matcher[parser->index] == '\0') { 996 | UPDATE_STATE(s_req_spaces_before_url); 997 | } else if (ch == matcher[parser->index]) { 998 | ; /* nada */ 999 | } else if (parser->method == HTTP_CONNECT) { 1000 | if (parser->index == 1 && ch == 'H') { 1001 | parser->method = HTTP_CHECKOUT; 1002 | } else if (parser->index == 2 && ch == 'P') { 1003 | parser->method = HTTP_COPY; 1004 | } else { 1005 | SET_ERRNO(HPE_INVALID_METHOD); 1006 | goto error; 1007 | } 1008 | } else if (parser->method == HTTP_MKCOL) { 1009 | if (parser->index == 1 && ch == 'O') { 1010 | parser->method = HTTP_MOVE; 1011 | } else if (parser->index == 1 && ch == 'E') { 1012 | parser->method = HTTP_MERGE; 1013 | } else if (parser->index == 1 && ch == '-') { 1014 | parser->method = HTTP_MSEARCH; 1015 | } else if (parser->index == 2 && ch == 'A') { 1016 | parser->method = HTTP_MKACTIVITY; 1017 | } else if (parser->index == 3 && ch == 'A') { 1018 | parser->method = HTTP_MKCALENDAR; 1019 | } else { 1020 | SET_ERRNO(HPE_INVALID_METHOD); 1021 | goto error; 1022 | } 1023 | } else if (parser->method == HTTP_SUBSCRIBE) { 1024 | if (parser->index == 1 && ch == 'E') { 1025 | parser->method = HTTP_SEARCH; 1026 | } else { 1027 | SET_ERRNO(HPE_INVALID_METHOD); 1028 | goto error; 1029 | } 1030 | } else if (parser->index == 1 && parser->method == HTTP_POST) { 1031 | if (ch == 'R') { 1032 | parser->method = HTTP_PROPFIND; /* or HTTP_PROPPATCH */ 1033 | } else if (ch == 'U') { 1034 | parser->method = HTTP_PUT; /* or HTTP_PURGE */ 1035 | } else if (ch == 'A') { 1036 | parser->method = HTTP_PATCH; 1037 | } else { 1038 | SET_ERRNO(HPE_INVALID_METHOD); 1039 | goto error; 1040 | } 1041 | } else if (parser->index == 2) { 1042 | if (parser->method == HTTP_PUT) { 1043 | if (ch == 'R') { 1044 | parser->method = HTTP_PURGE; 1045 | } else { 1046 | SET_ERRNO(HPE_INVALID_METHOD); 1047 | goto error; 1048 | } 1049 | } else if (parser->method == HTTP_UNLOCK) { 1050 | if (ch == 'S') { 1051 | parser->method = HTTP_UNSUBSCRIBE; 1052 | } else { 1053 | SET_ERRNO(HPE_INVALID_METHOD); 1054 | goto error; 1055 | } 1056 | } else { 1057 | SET_ERRNO(HPE_INVALID_METHOD); 1058 | goto error; 1059 | } 1060 | } else if (parser->index == 4 && parser->method == HTTP_PROPFIND && ch == 'P') { 1061 | parser->method = HTTP_PROPPATCH; 1062 | } else { 1063 | SET_ERRNO(HPE_INVALID_METHOD); 1064 | goto error; 1065 | } 1066 | 1067 | ++parser->index; 1068 | break; 1069 | } 1070 | 1071 | case s_req_spaces_before_url: 1072 | { 1073 | if (ch == ' ') break; 1074 | 1075 | MARK(url); 1076 | if (parser->method == HTTP_CONNECT) { 1077 | UPDATE_STATE(s_req_server_start); 1078 | } 1079 | 1080 | UPDATE_STATE(parse_url_char(CURRENT_STATE(), ch)); 1081 | if (UNLIKELY(CURRENT_STATE() == s_dead)) { 1082 | SET_ERRNO(HPE_INVALID_URL); 1083 | goto error; 1084 | } 1085 | 1086 | break; 1087 | } 1088 | 1089 | case s_req_schema: 1090 | case s_req_schema_slash: 1091 | case s_req_schema_slash_slash: 1092 | case s_req_server_start: 1093 | { 1094 | switch (ch) { 1095 | /* No whitespace allowed here */ 1096 | case ' ': 1097 | case CR: 1098 | case LF: 1099 | SET_ERRNO(HPE_INVALID_URL); 1100 | goto error; 1101 | default: 1102 | UPDATE_STATE(parse_url_char(CURRENT_STATE(), ch)); 1103 | if (UNLIKELY(CURRENT_STATE() == s_dead)) { 1104 | SET_ERRNO(HPE_INVALID_URL); 1105 | goto error; 1106 | } 1107 | } 1108 | 1109 | break; 1110 | } 1111 | 1112 | case s_req_server: 1113 | case s_req_server_with_at: 1114 | case s_req_path: 1115 | case s_req_query_string_start: 1116 | case s_req_query_string: 1117 | case s_req_fragment_start: 1118 | case s_req_fragment: 1119 | { 1120 | switch (ch) { 1121 | case ' ': 1122 | UPDATE_STATE(s_req_http_start); 1123 | CALLBACK_DATA(url); 1124 | break; 1125 | case CR: 1126 | case LF: 1127 | parser->http_major = 0; 1128 | parser->http_minor = 9; 1129 | UPDATE_STATE((ch == CR) ? 1130 | s_req_line_almost_done : 1131 | s_header_field_start); 1132 | CALLBACK_DATA(url); 1133 | break; 1134 | default: 1135 | UPDATE_STATE(parse_url_char(CURRENT_STATE(), ch)); 1136 | if (UNLIKELY(CURRENT_STATE() == s_dead)) { 1137 | SET_ERRNO(HPE_INVALID_URL); 1138 | goto error; 1139 | } 1140 | } 1141 | break; 1142 | } 1143 | 1144 | case s_req_http_start: 1145 | switch (ch) { 1146 | case 'H': 1147 | UPDATE_STATE(s_req_http_H); 1148 | break; 1149 | case ' ': 1150 | break; 1151 | default: 1152 | SET_ERRNO(HPE_INVALID_CONSTANT); 1153 | goto error; 1154 | } 1155 | break; 1156 | 1157 | case s_req_http_H: 1158 | STRICT_CHECK(ch != 'T'); 1159 | UPDATE_STATE(s_req_http_HT); 1160 | break; 1161 | 1162 | case s_req_http_HT: 1163 | STRICT_CHECK(ch != 'T'); 1164 | UPDATE_STATE(s_req_http_HTT); 1165 | break; 1166 | 1167 | case s_req_http_HTT: 1168 | STRICT_CHECK(ch != 'P'); 1169 | UPDATE_STATE(s_req_http_HTTP); 1170 | break; 1171 | 1172 | case s_req_http_HTTP: 1173 | STRICT_CHECK(ch != '/'); 1174 | UPDATE_STATE(s_req_first_http_major); 1175 | break; 1176 | 1177 | /* first digit of major HTTP version */ 1178 | case s_req_first_http_major: 1179 | if (UNLIKELY(ch < '1' || ch > '9')) { 1180 | SET_ERRNO(HPE_INVALID_VERSION); 1181 | goto error; 1182 | } 1183 | 1184 | parser->http_major = ch - '0'; 1185 | UPDATE_STATE(s_req_http_major); 1186 | break; 1187 | 1188 | /* major HTTP version or dot */ 1189 | case s_req_http_major: 1190 | { 1191 | if (ch == '.') { 1192 | UPDATE_STATE(s_req_first_http_minor); 1193 | break; 1194 | } 1195 | 1196 | if (UNLIKELY(!IS_NUM(ch))) { 1197 | SET_ERRNO(HPE_INVALID_VERSION); 1198 | goto error; 1199 | } 1200 | 1201 | parser->http_major *= 10; 1202 | parser->http_major += ch - '0'; 1203 | 1204 | if (UNLIKELY(parser->http_major > 999)) { 1205 | SET_ERRNO(HPE_INVALID_VERSION); 1206 | goto error; 1207 | } 1208 | 1209 | break; 1210 | } 1211 | 1212 | /* first digit of minor HTTP version */ 1213 | case s_req_first_http_minor: 1214 | if (UNLIKELY(!IS_NUM(ch))) { 1215 | SET_ERRNO(HPE_INVALID_VERSION); 1216 | goto error; 1217 | } 1218 | 1219 | parser->http_minor = ch - '0'; 1220 | UPDATE_STATE(s_req_http_minor); 1221 | break; 1222 | 1223 | /* minor HTTP version or end of request line */ 1224 | case s_req_http_minor: 1225 | { 1226 | if (ch == CR) { 1227 | UPDATE_STATE(s_req_line_almost_done); 1228 | break; 1229 | } 1230 | 1231 | if (ch == LF) { 1232 | UPDATE_STATE(s_header_field_start); 1233 | break; 1234 | } 1235 | 1236 | /* XXX allow spaces after digit? */ 1237 | 1238 | if (UNLIKELY(!IS_NUM(ch))) { 1239 | SET_ERRNO(HPE_INVALID_VERSION); 1240 | goto error; 1241 | } 1242 | 1243 | parser->http_minor *= 10; 1244 | parser->http_minor += ch - '0'; 1245 | 1246 | if (UNLIKELY(parser->http_minor > 999)) { 1247 | SET_ERRNO(HPE_INVALID_VERSION); 1248 | goto error; 1249 | } 1250 | 1251 | break; 1252 | } 1253 | 1254 | /* end of request line */ 1255 | case s_req_line_almost_done: 1256 | { 1257 | if (UNLIKELY(ch != LF)) { 1258 | SET_ERRNO(HPE_LF_EXPECTED); 1259 | goto error; 1260 | } 1261 | 1262 | UPDATE_STATE(s_header_field_start); 1263 | break; 1264 | } 1265 | 1266 | case s_header_field_start: 1267 | { 1268 | if (ch == CR) { 1269 | UPDATE_STATE(s_headers_almost_done); 1270 | break; 1271 | } 1272 | 1273 | if (ch == LF) { 1274 | /* they might be just sending \n instead of \r\n so this would be 1275 | * the second \n to denote the end of headers*/ 1276 | UPDATE_STATE(s_headers_almost_done); 1277 | REEXECUTE(); 1278 | } 1279 | 1280 | c = TOKEN(ch); 1281 | 1282 | if (UNLIKELY(!c)) { 1283 | SET_ERRNO(HPE_INVALID_HEADER_TOKEN); 1284 | goto error; 1285 | } 1286 | 1287 | MARK(header_field); 1288 | 1289 | parser->index = 0; 1290 | UPDATE_STATE(s_header_field); 1291 | 1292 | switch (c) { 1293 | case 'c': 1294 | parser->header_state = h_C; 1295 | break; 1296 | 1297 | case 'p': 1298 | parser->header_state = h_matching_proxy_connection; 1299 | break; 1300 | 1301 | case 't': 1302 | parser->header_state = h_matching_transfer_encoding; 1303 | break; 1304 | 1305 | case 'u': 1306 | parser->header_state = h_matching_upgrade; 1307 | break; 1308 | 1309 | default: 1310 | parser->header_state = h_general; 1311 | break; 1312 | } 1313 | break; 1314 | } 1315 | 1316 | case s_header_field: 1317 | { 1318 | const char* start = p; 1319 | for (; p != data + len; p++) { 1320 | ch = *p; 1321 | c = TOKEN(ch); 1322 | 1323 | if (!c) 1324 | break; 1325 | 1326 | switch (parser->header_state) { 1327 | case h_general: 1328 | break; 1329 | 1330 | case h_C: 1331 | parser->index++; 1332 | parser->header_state = (c == 'o' ? h_CO : h_general); 1333 | break; 1334 | 1335 | case h_CO: 1336 | parser->index++; 1337 | parser->header_state = (c == 'n' ? h_CON : h_general); 1338 | break; 1339 | 1340 | case h_CON: 1341 | parser->index++; 1342 | switch (c) { 1343 | case 'n': 1344 | parser->header_state = h_matching_connection; 1345 | break; 1346 | case 't': 1347 | parser->header_state = h_matching_content_length; 1348 | break; 1349 | default: 1350 | parser->header_state = h_general; 1351 | break; 1352 | } 1353 | break; 1354 | 1355 | /* connection */ 1356 | 1357 | case h_matching_connection: 1358 | parser->index++; 1359 | if (parser->index > sizeof(CONNECTION)-1 1360 | || c != CONNECTION[parser->index]) { 1361 | parser->header_state = h_general; 1362 | } else if (parser->index == sizeof(CONNECTION)-2) { 1363 | parser->header_state = h_connection; 1364 | } 1365 | break; 1366 | 1367 | /* proxy-connection */ 1368 | 1369 | case h_matching_proxy_connection: 1370 | parser->index++; 1371 | if (parser->index > sizeof(PROXY_CONNECTION)-1 1372 | || c != PROXY_CONNECTION[parser->index]) { 1373 | parser->header_state = h_general; 1374 | } else if (parser->index == sizeof(PROXY_CONNECTION)-2) { 1375 | parser->header_state = h_connection; 1376 | } 1377 | break; 1378 | 1379 | /* content-length */ 1380 | 1381 | case h_matching_content_length: 1382 | parser->index++; 1383 | if (parser->index > sizeof(CONTENT_LENGTH)-1 1384 | || c != CONTENT_LENGTH[parser->index]) { 1385 | parser->header_state = h_general; 1386 | } else if (parser->index == sizeof(CONTENT_LENGTH)-2) { 1387 | parser->header_state = h_content_length; 1388 | } 1389 | break; 1390 | 1391 | /* transfer-encoding */ 1392 | 1393 | case h_matching_transfer_encoding: 1394 | parser->index++; 1395 | if (parser->index > sizeof(TRANSFER_ENCODING)-1 1396 | || c != TRANSFER_ENCODING[parser->index]) { 1397 | parser->header_state = h_general; 1398 | } else if (parser->index == sizeof(TRANSFER_ENCODING)-2) { 1399 | parser->header_state = h_transfer_encoding; 1400 | } 1401 | break; 1402 | 1403 | /* upgrade */ 1404 | 1405 | case h_matching_upgrade: 1406 | parser->index++; 1407 | if (parser->index > sizeof(UPGRADE)-1 1408 | || c != UPGRADE[parser->index]) { 1409 | parser->header_state = h_general; 1410 | } else if (parser->index == sizeof(UPGRADE)-2) { 1411 | parser->header_state = h_upgrade; 1412 | } 1413 | break; 1414 | 1415 | case h_connection: 1416 | case h_content_length: 1417 | case h_transfer_encoding: 1418 | case h_upgrade: 1419 | if (ch != ' ') parser->header_state = h_general; 1420 | break; 1421 | 1422 | default: 1423 | assert(0 && "Unknown header_state"); 1424 | break; 1425 | } 1426 | } 1427 | 1428 | COUNT_HEADER_SIZE(p - start); 1429 | 1430 | if (p == data + len) { 1431 | --p; 1432 | break; 1433 | } 1434 | 1435 | if (ch == ':') { 1436 | UPDATE_STATE(s_header_value_discard_ws); 1437 | CALLBACK_DATA(header_field); 1438 | break; 1439 | } 1440 | 1441 | SET_ERRNO(HPE_INVALID_HEADER_TOKEN); 1442 | goto error; 1443 | } 1444 | 1445 | case s_header_value_discard_ws: 1446 | if (ch == ' ' || ch == '\t') break; 1447 | 1448 | if (ch == CR) { 1449 | UPDATE_STATE(s_header_value_discard_ws_almost_done); 1450 | break; 1451 | } 1452 | 1453 | if (ch == LF) { 1454 | UPDATE_STATE(s_header_value_discard_lws); 1455 | break; 1456 | } 1457 | 1458 | /* FALLTHROUGH */ 1459 | 1460 | case s_header_value_start: 1461 | { 1462 | MARK(header_value); 1463 | 1464 | UPDATE_STATE(s_header_value); 1465 | parser->index = 0; 1466 | 1467 | c = LOWER(ch); 1468 | 1469 | switch (parser->header_state) { 1470 | case h_upgrade: 1471 | parser->flags |= F_UPGRADE; 1472 | parser->header_state = h_general; 1473 | break; 1474 | 1475 | case h_transfer_encoding: 1476 | /* looking for 'Transfer-Encoding: chunked' */ 1477 | if ('c' == c) { 1478 | parser->header_state = h_matching_transfer_encoding_chunked; 1479 | } else { 1480 | parser->header_state = h_general; 1481 | } 1482 | break; 1483 | 1484 | case h_content_length: 1485 | if (UNLIKELY(!IS_NUM(ch))) { 1486 | SET_ERRNO(HPE_INVALID_CONTENT_LENGTH); 1487 | goto error; 1488 | } 1489 | 1490 | parser->content_length = ch - '0'; 1491 | break; 1492 | 1493 | case h_connection: 1494 | /* looking for 'Connection: keep-alive' */ 1495 | if (c == 'k') { 1496 | parser->header_state = h_matching_connection_keep_alive; 1497 | /* looking for 'Connection: close' */ 1498 | } else if (c == 'c') { 1499 | parser->header_state = h_matching_connection_close; 1500 | } else if (c == 'u') { 1501 | parser->header_state = h_matching_connection_upgrade; 1502 | } else { 1503 | parser->header_state = h_matching_connection_token; 1504 | } 1505 | break; 1506 | 1507 | /* Multi-value `Connection` header */ 1508 | case h_matching_connection_token_start: 1509 | break; 1510 | 1511 | default: 1512 | parser->header_state = h_general; 1513 | break; 1514 | } 1515 | break; 1516 | } 1517 | 1518 | case s_header_value: 1519 | { 1520 | const char* start = p; 1521 | enum header_states h_state = (enum header_states) parser->header_state; 1522 | for (; p != data + len; p++) { 1523 | ch = *p; 1524 | if (ch == CR) { 1525 | UPDATE_STATE(s_header_almost_done); 1526 | parser->header_state = h_state; 1527 | CALLBACK_DATA(header_value); 1528 | break; 1529 | } 1530 | 1531 | if (ch == LF) { 1532 | UPDATE_STATE(s_header_almost_done); 1533 | COUNT_HEADER_SIZE(p - start); 1534 | parser->header_state = h_state; 1535 | CALLBACK_DATA_NOADVANCE(header_value); 1536 | REEXECUTE(); 1537 | } 1538 | 1539 | c = LOWER(ch); 1540 | 1541 | switch (h_state) { 1542 | case h_general: 1543 | { 1544 | const char* p_cr; 1545 | const char* p_lf; 1546 | size_t limit = data + len - p; 1547 | 1548 | limit = MIN(limit, HTTP_MAX_HEADER_SIZE); 1549 | 1550 | p_cr = (const char*) memchr(p, CR, limit); 1551 | p_lf = (const char*) memchr(p, LF, limit); 1552 | if (p_cr != NULL) { 1553 | if (p_lf != NULL && p_cr >= p_lf) 1554 | p = p_lf; 1555 | else 1556 | p = p_cr; 1557 | } else if (UNLIKELY(p_lf != NULL)) { 1558 | p = p_lf; 1559 | } else { 1560 | p = data + len; 1561 | } 1562 | --p; 1563 | 1564 | break; 1565 | } 1566 | 1567 | case h_connection: 1568 | case h_transfer_encoding: 1569 | assert(0 && "Shouldn't get here."); 1570 | break; 1571 | 1572 | case h_content_length: 1573 | { 1574 | uint64_t t; 1575 | 1576 | if (ch == ' ') break; 1577 | 1578 | if (UNLIKELY(!IS_NUM(ch))) { 1579 | SET_ERRNO(HPE_INVALID_CONTENT_LENGTH); 1580 | parser->header_state = h_state; 1581 | goto error; 1582 | } 1583 | 1584 | t = parser->content_length; 1585 | t *= 10; 1586 | t += ch - '0'; 1587 | 1588 | /* Overflow? Test against a conservative limit for simplicity. */ 1589 | if (UNLIKELY((ULLONG_MAX - 10) / 10 < parser->content_length)) { 1590 | SET_ERRNO(HPE_INVALID_CONTENT_LENGTH); 1591 | parser->header_state = h_state; 1592 | goto error; 1593 | } 1594 | 1595 | parser->content_length = t; 1596 | break; 1597 | } 1598 | 1599 | /* Transfer-Encoding: chunked */ 1600 | case h_matching_transfer_encoding_chunked: 1601 | parser->index++; 1602 | if (parser->index > sizeof(CHUNKED)-1 1603 | || c != CHUNKED[parser->index]) { 1604 | h_state = h_general; 1605 | } else if (parser->index == sizeof(CHUNKED)-2) { 1606 | h_state = h_transfer_encoding_chunked; 1607 | } 1608 | break; 1609 | 1610 | case h_matching_connection_token_start: 1611 | /* looking for 'Connection: keep-alive' */ 1612 | if (c == 'k') { 1613 | h_state = h_matching_connection_keep_alive; 1614 | /* looking for 'Connection: close' */ 1615 | } else if (c == 'c') { 1616 | h_state = h_matching_connection_close; 1617 | } else if (c == 'u') { 1618 | h_state = h_matching_connection_upgrade; 1619 | } else if (STRICT_TOKEN(c)) { 1620 | h_state = h_matching_connection_token; 1621 | } else if (c == ' ' || c == '\t') { 1622 | /* Skip lws */ 1623 | } else { 1624 | h_state = h_general; 1625 | } 1626 | break; 1627 | 1628 | /* looking for 'Connection: keep-alive' */ 1629 | case h_matching_connection_keep_alive: 1630 | parser->index++; 1631 | if (parser->index > sizeof(KEEP_ALIVE)-1 1632 | || c != KEEP_ALIVE[parser->index]) { 1633 | h_state = h_matching_connection_token; 1634 | } else if (parser->index == sizeof(KEEP_ALIVE)-2) { 1635 | h_state = h_connection_keep_alive; 1636 | } 1637 | break; 1638 | 1639 | /* looking for 'Connection: close' */ 1640 | case h_matching_connection_close: 1641 | parser->index++; 1642 | if (parser->index > sizeof(CLOSE)-1 || c != CLOSE[parser->index]) { 1643 | h_state = h_matching_connection_token; 1644 | } else if (parser->index == sizeof(CLOSE)-2) { 1645 | h_state = h_connection_close; 1646 | } 1647 | break; 1648 | 1649 | /* looking for 'Connection: upgrade' */ 1650 | case h_matching_connection_upgrade: 1651 | parser->index++; 1652 | if (parser->index > sizeof(UPGRADE) - 1 || 1653 | c != UPGRADE[parser->index]) { 1654 | h_state = h_matching_connection_token; 1655 | } else if (parser->index == sizeof(UPGRADE)-2) { 1656 | h_state = h_connection_upgrade; 1657 | } 1658 | break; 1659 | 1660 | case h_matching_connection_token: 1661 | if (ch == ',') { 1662 | h_state = h_matching_connection_token_start; 1663 | parser->index = 0; 1664 | } 1665 | break; 1666 | 1667 | case h_transfer_encoding_chunked: 1668 | if (ch != ' ') h_state = h_general; 1669 | break; 1670 | 1671 | case h_connection_keep_alive: 1672 | case h_connection_close: 1673 | case h_connection_upgrade: 1674 | if (ch == ',') { 1675 | if (h_state == h_connection_keep_alive) { 1676 | parser->flags |= F_CONNECTION_KEEP_ALIVE; 1677 | } else if (h_state == h_connection_close) { 1678 | parser->flags |= F_CONNECTION_CLOSE; 1679 | } else if (h_state == h_connection_upgrade) { 1680 | parser->flags |= F_CONNECTION_UPGRADE; 1681 | } 1682 | h_state = h_matching_connection_token_start; 1683 | parser->index = 0; 1684 | } else if (ch != ' ') { 1685 | h_state = h_matching_connection_token; 1686 | } 1687 | break; 1688 | 1689 | default: 1690 | UPDATE_STATE(s_header_value); 1691 | h_state = h_general; 1692 | break; 1693 | } 1694 | } 1695 | parser->header_state = h_state; 1696 | 1697 | COUNT_HEADER_SIZE(p - start); 1698 | 1699 | if (p == data + len) 1700 | --p; 1701 | break; 1702 | } 1703 | 1704 | case s_header_almost_done: 1705 | { 1706 | STRICT_CHECK(ch != LF); 1707 | 1708 | UPDATE_STATE(s_header_value_lws); 1709 | break; 1710 | } 1711 | 1712 | case s_header_value_lws: 1713 | { 1714 | if (ch == ' ' || ch == '\t') { 1715 | UPDATE_STATE(s_header_value_start); 1716 | REEXECUTE(); 1717 | } 1718 | 1719 | /* finished the header */ 1720 | switch (parser->header_state) { 1721 | case h_connection_keep_alive: 1722 | parser->flags |= F_CONNECTION_KEEP_ALIVE; 1723 | break; 1724 | case h_connection_close: 1725 | parser->flags |= F_CONNECTION_CLOSE; 1726 | break; 1727 | case h_transfer_encoding_chunked: 1728 | parser->flags |= F_CHUNKED; 1729 | break; 1730 | case h_connection_upgrade: 1731 | parser->flags |= F_CONNECTION_UPGRADE; 1732 | break; 1733 | default: 1734 | break; 1735 | } 1736 | 1737 | UPDATE_STATE(s_header_field_start); 1738 | REEXECUTE(); 1739 | } 1740 | 1741 | case s_header_value_discard_ws_almost_done: 1742 | { 1743 | STRICT_CHECK(ch != LF); 1744 | UPDATE_STATE(s_header_value_discard_lws); 1745 | break; 1746 | } 1747 | 1748 | case s_header_value_discard_lws: 1749 | { 1750 | if (ch == ' ' || ch == '\t') { 1751 | UPDATE_STATE(s_header_value_discard_ws); 1752 | break; 1753 | } else { 1754 | switch (parser->header_state) { 1755 | case h_connection_keep_alive: 1756 | parser->flags |= F_CONNECTION_KEEP_ALIVE; 1757 | break; 1758 | case h_connection_close: 1759 | parser->flags |= F_CONNECTION_CLOSE; 1760 | break; 1761 | case h_connection_upgrade: 1762 | parser->flags |= F_CONNECTION_UPGRADE; 1763 | break; 1764 | case h_transfer_encoding_chunked: 1765 | parser->flags |= F_CHUNKED; 1766 | break; 1767 | default: 1768 | break; 1769 | } 1770 | 1771 | /* header value was empty */ 1772 | MARK(header_value); 1773 | UPDATE_STATE(s_header_field_start); 1774 | CALLBACK_DATA_NOADVANCE(header_value); 1775 | REEXECUTE(); 1776 | } 1777 | } 1778 | 1779 | case s_headers_almost_done: 1780 | { 1781 | STRICT_CHECK(ch != LF); 1782 | 1783 | if (parser->flags & F_TRAILING) { 1784 | /* End of a chunked request */ 1785 | UPDATE_STATE(NEW_MESSAGE()); 1786 | CALLBACK_NOTIFY(message_complete); 1787 | break; 1788 | } 1789 | 1790 | UPDATE_STATE(s_headers_done); 1791 | 1792 | /* Set this here so that on_headers_complete() callbacks can see it */ 1793 | parser->upgrade = 1794 | ((parser->flags & (F_UPGRADE | F_CONNECTION_UPGRADE)) == 1795 | (F_UPGRADE | F_CONNECTION_UPGRADE) || 1796 | parser->method == HTTP_CONNECT); 1797 | 1798 | /* Here we call the headers_complete callback. This is somewhat 1799 | * different than other callbacks because if the user returns 1, we 1800 | * will interpret that as saying that this message has no body. This 1801 | * is needed for the annoying case of recieving a response to a HEAD 1802 | * request. 1803 | * 1804 | * We'd like to use CALLBACK_NOTIFY_NOADVANCE() here but we cannot, so 1805 | * we have to simulate it by handling a change in errno below. 1806 | */ 1807 | if (settings->on_headers_complete) { 1808 | switch (settings->on_headers_complete(parser)) { 1809 | case 0: 1810 | break; 1811 | 1812 | case 1: 1813 | parser->flags |= F_SKIPBODY; 1814 | break; 1815 | 1816 | default: 1817 | SET_ERRNO(HPE_CB_headers_complete); 1818 | RETURN(p - data); /* Error */ 1819 | } 1820 | } 1821 | 1822 | if (HTTP_PARSER_ERRNO(parser) != HPE_OK) { 1823 | RETURN(p - data); 1824 | } 1825 | 1826 | REEXECUTE(); 1827 | } 1828 | 1829 | case s_headers_done: 1830 | { 1831 | STRICT_CHECK(ch != LF); 1832 | 1833 | parser->nread = 0; 1834 | 1835 | /* Exit, the rest of the connect is in a different protocol. */ 1836 | if (parser->upgrade) { 1837 | UPDATE_STATE(NEW_MESSAGE()); 1838 | CALLBACK_NOTIFY(message_complete); 1839 | RETURN((p - data) + 1); 1840 | } 1841 | 1842 | if (parser->flags & F_SKIPBODY) { 1843 | UPDATE_STATE(NEW_MESSAGE()); 1844 | CALLBACK_NOTIFY(message_complete); 1845 | } else if (parser->flags & F_CHUNKED) { 1846 | /* chunked encoding - ignore Content-Length header */ 1847 | UPDATE_STATE(s_chunk_size_start); 1848 | } else { 1849 | if (parser->content_length == 0) { 1850 | /* Content-Length header given but zero: Content-Length: 0\r\n */ 1851 | UPDATE_STATE(NEW_MESSAGE()); 1852 | CALLBACK_NOTIFY(message_complete); 1853 | } else if (parser->content_length != ULLONG_MAX) { 1854 | /* Content-Length header given and non-zero */ 1855 | UPDATE_STATE(s_body_identity); 1856 | } else { 1857 | if (parser->type == HTTP_REQUEST || 1858 | !http_message_needs_eof(parser)) { 1859 | /* Assume content-length 0 - read the next */ 1860 | UPDATE_STATE(NEW_MESSAGE()); 1861 | CALLBACK_NOTIFY(message_complete); 1862 | } else { 1863 | /* Read body until EOF */ 1864 | UPDATE_STATE(s_body_identity_eof); 1865 | } 1866 | } 1867 | } 1868 | 1869 | break; 1870 | } 1871 | 1872 | case s_body_identity: 1873 | { 1874 | uint64_t to_read = MIN(parser->content_length, 1875 | (uint64_t) ((data + len) - p)); 1876 | 1877 | assert(parser->content_length != 0 1878 | && parser->content_length != ULLONG_MAX); 1879 | 1880 | /* The difference between advancing content_length and p is because 1881 | * the latter will automaticaly advance on the next loop iteration. 1882 | * Further, if content_length ends up at 0, we want to see the last 1883 | * byte again for our message complete callback. 1884 | */ 1885 | MARK(body); 1886 | parser->content_length -= to_read; 1887 | p += to_read - 1; 1888 | 1889 | if (parser->content_length == 0) { 1890 | UPDATE_STATE(s_message_done); 1891 | 1892 | /* Mimic CALLBACK_DATA_NOADVANCE() but with one extra byte. 1893 | * 1894 | * The alternative to doing this is to wait for the next byte to 1895 | * trigger the data callback, just as in every other case. The 1896 | * problem with this is that this makes it difficult for the test 1897 | * harness to distinguish between complete-on-EOF and 1898 | * complete-on-length. It's not clear that this distinction is 1899 | * important for applications, but let's keep it for now. 1900 | */ 1901 | CALLBACK_DATA_(body, p - body_mark + 1, p - data); 1902 | REEXECUTE(); 1903 | } 1904 | 1905 | break; 1906 | } 1907 | 1908 | /* read until EOF */ 1909 | case s_body_identity_eof: 1910 | MARK(body); 1911 | p = data + len - 1; 1912 | 1913 | break; 1914 | 1915 | case s_message_done: 1916 | UPDATE_STATE(NEW_MESSAGE()); 1917 | CALLBACK_NOTIFY(message_complete); 1918 | break; 1919 | 1920 | case s_chunk_size_start: 1921 | { 1922 | assert(parser->nread == 1); 1923 | assert(parser->flags & F_CHUNKED); 1924 | 1925 | unhex_val = unhex[(unsigned char)ch]; 1926 | if (UNLIKELY(unhex_val == -1)) { 1927 | SET_ERRNO(HPE_INVALID_CHUNK_SIZE); 1928 | goto error; 1929 | } 1930 | 1931 | parser->content_length = unhex_val; 1932 | UPDATE_STATE(s_chunk_size); 1933 | break; 1934 | } 1935 | 1936 | case s_chunk_size: 1937 | { 1938 | uint64_t t; 1939 | 1940 | assert(parser->flags & F_CHUNKED); 1941 | 1942 | if (ch == CR) { 1943 | UPDATE_STATE(s_chunk_size_almost_done); 1944 | break; 1945 | } 1946 | 1947 | unhex_val = unhex[(unsigned char)ch]; 1948 | 1949 | if (unhex_val == -1) { 1950 | if (ch == ';' || ch == ' ') { 1951 | UPDATE_STATE(s_chunk_parameters); 1952 | break; 1953 | } 1954 | 1955 | SET_ERRNO(HPE_INVALID_CHUNK_SIZE); 1956 | goto error; 1957 | } 1958 | 1959 | t = parser->content_length; 1960 | t *= 16; 1961 | t += unhex_val; 1962 | 1963 | /* Overflow? Test against a conservative limit for simplicity. */ 1964 | if (UNLIKELY((ULLONG_MAX - 16) / 16 < parser->content_length)) { 1965 | SET_ERRNO(HPE_INVALID_CONTENT_LENGTH); 1966 | goto error; 1967 | } 1968 | 1969 | parser->content_length = t; 1970 | break; 1971 | } 1972 | 1973 | case s_chunk_parameters: 1974 | { 1975 | assert(parser->flags & F_CHUNKED); 1976 | /* just ignore this shit. TODO check for overflow */ 1977 | if (ch == CR) { 1978 | UPDATE_STATE(s_chunk_size_almost_done); 1979 | break; 1980 | } 1981 | break; 1982 | } 1983 | 1984 | case s_chunk_size_almost_done: 1985 | { 1986 | assert(parser->flags & F_CHUNKED); 1987 | STRICT_CHECK(ch != LF); 1988 | 1989 | parser->nread = 0; 1990 | 1991 | if (parser->content_length == 0) { 1992 | parser->flags |= F_TRAILING; 1993 | UPDATE_STATE(s_header_field_start); 1994 | } else { 1995 | UPDATE_STATE(s_chunk_data); 1996 | } 1997 | break; 1998 | } 1999 | 2000 | case s_chunk_data: 2001 | { 2002 | uint64_t to_read = MIN(parser->content_length, 2003 | (uint64_t) ((data + len) - p)); 2004 | 2005 | assert(parser->flags & F_CHUNKED); 2006 | assert(parser->content_length != 0 2007 | && parser->content_length != ULLONG_MAX); 2008 | 2009 | /* See the explanation in s_body_identity for why the content 2010 | * length and data pointers are managed this way. 2011 | */ 2012 | MARK(body); 2013 | parser->content_length -= to_read; 2014 | p += to_read - 1; 2015 | 2016 | if (parser->content_length == 0) { 2017 | UPDATE_STATE(s_chunk_data_almost_done); 2018 | } 2019 | 2020 | break; 2021 | } 2022 | 2023 | case s_chunk_data_almost_done: 2024 | assert(parser->flags & F_CHUNKED); 2025 | assert(parser->content_length == 0); 2026 | STRICT_CHECK(ch != CR); 2027 | UPDATE_STATE(s_chunk_data_done); 2028 | CALLBACK_DATA(body); 2029 | break; 2030 | 2031 | case s_chunk_data_done: 2032 | assert(parser->flags & F_CHUNKED); 2033 | STRICT_CHECK(ch != LF); 2034 | parser->nread = 0; 2035 | UPDATE_STATE(s_chunk_size_start); 2036 | break; 2037 | 2038 | default: 2039 | assert(0 && "unhandled state"); 2040 | SET_ERRNO(HPE_INVALID_INTERNAL_STATE); 2041 | goto error; 2042 | } 2043 | } 2044 | 2045 | /* Run callbacks for any marks that we have leftover after we ran our of 2046 | * bytes. There should be at most one of these set, so it's OK to invoke 2047 | * them in series (unset marks will not result in callbacks). 2048 | * 2049 | * We use the NOADVANCE() variety of callbacks here because 'p' has already 2050 | * overflowed 'data' and this allows us to correct for the off-by-one that 2051 | * we'd otherwise have (since CALLBACK_DATA() is meant to be run with a 'p' 2052 | * value that's in-bounds). 2053 | */ 2054 | 2055 | assert(((header_field_mark ? 1 : 0) + 2056 | (header_value_mark ? 1 : 0) + 2057 | (url_mark ? 1 : 0) + 2058 | (body_mark ? 1 : 0) + 2059 | (status_mark ? 1 : 0)) <= 1); 2060 | 2061 | CALLBACK_DATA_NOADVANCE(header_field); 2062 | CALLBACK_DATA_NOADVANCE(header_value); 2063 | CALLBACK_DATA_NOADVANCE(url); 2064 | CALLBACK_DATA_NOADVANCE(body); 2065 | CALLBACK_DATA_NOADVANCE(status); 2066 | 2067 | RETURN(len); 2068 | 2069 | error: 2070 | if (HTTP_PARSER_ERRNO(parser) == HPE_OK) { 2071 | SET_ERRNO(HPE_UNKNOWN); 2072 | } 2073 | 2074 | RETURN(p - data); 2075 | } 2076 | 2077 | 2078 | /* Does the parser need to see an EOF to find the end of the message? */ 2079 | int 2080 | http_message_needs_eof (const http_parser *parser) 2081 | { 2082 | if (parser->type == HTTP_REQUEST) { 2083 | return 0; 2084 | } 2085 | 2086 | /* See RFC 2616 section 4.4 */ 2087 | if (parser->status_code / 100 == 1 || /* 1xx e.g. Continue */ 2088 | parser->status_code == 204 || /* No Content */ 2089 | parser->status_code == 304 || /* Not Modified */ 2090 | parser->flags & F_SKIPBODY) { /* response to a HEAD request */ 2091 | return 0; 2092 | } 2093 | 2094 | if ((parser->flags & F_CHUNKED) || parser->content_length != ULLONG_MAX) { 2095 | return 0; 2096 | } 2097 | 2098 | return 1; 2099 | } 2100 | 2101 | 2102 | int 2103 | http_should_keep_alive (const http_parser *parser) 2104 | { 2105 | if (parser->http_major > 0 && parser->http_minor > 0) { 2106 | /* HTTP/1.1 */ 2107 | if (parser->flags & F_CONNECTION_CLOSE) { 2108 | return 0; 2109 | } 2110 | } else { 2111 | /* HTTP/1.0 or earlier */ 2112 | if (!(parser->flags & F_CONNECTION_KEEP_ALIVE)) { 2113 | return 0; 2114 | } 2115 | } 2116 | 2117 | return !http_message_needs_eof(parser); 2118 | } 2119 | 2120 | 2121 | const char * 2122 | http_method_str (enum http_method m) 2123 | { 2124 | return ELEM_AT(method_strings, m, ""); 2125 | } 2126 | 2127 | 2128 | void 2129 | http_parser_init (http_parser *parser, enum http_parser_type t) 2130 | { 2131 | void *data = parser->data; /* preserve application data */ 2132 | memset(parser, 0, sizeof(*parser)); 2133 | parser->data = data; 2134 | parser->type = t; 2135 | parser->state = (t == HTTP_REQUEST ? s_start_req : (t == HTTP_RESPONSE ? s_start_res : s_start_req_or_res)); 2136 | parser->http_errno = HPE_OK; 2137 | } 2138 | 2139 | void 2140 | http_parser_settings_init(http_parser_settings *settings) 2141 | { 2142 | memset(settings, 0, sizeof(*settings)); 2143 | } 2144 | 2145 | const char * 2146 | http_errno_name(enum http_errno err) { 2147 | assert(err < (sizeof(http_strerror_tab)/sizeof(http_strerror_tab[0]))); 2148 | return http_strerror_tab[err].name; 2149 | } 2150 | 2151 | const char * 2152 | http_errno_description(enum http_errno err) { 2153 | assert(err < (sizeof(http_strerror_tab)/sizeof(http_strerror_tab[0]))); 2154 | return http_strerror_tab[err].description; 2155 | } 2156 | 2157 | static enum http_host_state 2158 | http_parse_host_char(enum http_host_state s, const char ch) { 2159 | switch(s) { 2160 | case s_http_userinfo: 2161 | case s_http_userinfo_start: 2162 | if (ch == '@') { 2163 | return s_http_host_start; 2164 | } 2165 | 2166 | if (IS_USERINFO_CHAR(ch)) { 2167 | return s_http_userinfo; 2168 | } 2169 | break; 2170 | 2171 | case s_http_host_start: 2172 | if (ch == '[') { 2173 | return s_http_host_v6_start; 2174 | } 2175 | 2176 | if (IS_HOST_CHAR(ch)) { 2177 | return s_http_host; 2178 | } 2179 | 2180 | break; 2181 | 2182 | case s_http_host: 2183 | if (IS_HOST_CHAR(ch)) { 2184 | return s_http_host; 2185 | } 2186 | 2187 | /* FALLTHROUGH */ 2188 | case s_http_host_v6_end: 2189 | if (ch == ':') { 2190 | return s_http_host_port_start; 2191 | } 2192 | 2193 | break; 2194 | 2195 | case s_http_host_v6: 2196 | if (ch == ']') { 2197 | return s_http_host_v6_end; 2198 | } 2199 | 2200 | /* FALLTHROUGH */ 2201 | case s_http_host_v6_start: 2202 | if (IS_HEX(ch) || ch == ':' || ch == '.') { 2203 | return s_http_host_v6; 2204 | } 2205 | 2206 | break; 2207 | 2208 | case s_http_host_port: 2209 | case s_http_host_port_start: 2210 | if (IS_NUM(ch)) { 2211 | return s_http_host_port; 2212 | } 2213 | 2214 | break; 2215 | 2216 | default: 2217 | break; 2218 | } 2219 | return s_http_host_dead; 2220 | } 2221 | 2222 | static int 2223 | http_parse_host(const char * buf, struct http_parser_url *u, int found_at) { 2224 | enum http_host_state s; 2225 | 2226 | const char *p; 2227 | size_t buflen = u->field_data[UF_HOST].off + u->field_data[UF_HOST].len; 2228 | 2229 | u->field_data[UF_HOST].len = 0; 2230 | 2231 | s = found_at ? s_http_userinfo_start : s_http_host_start; 2232 | 2233 | for (p = buf + u->field_data[UF_HOST].off; p < buf + buflen; p++) { 2234 | enum http_host_state new_s = http_parse_host_char(s, *p); 2235 | 2236 | if (new_s == s_http_host_dead) { 2237 | return 1; 2238 | } 2239 | 2240 | switch(new_s) { 2241 | case s_http_host: 2242 | if (s != s_http_host) { 2243 | u->field_data[UF_HOST].off = p - buf; 2244 | } 2245 | u->field_data[UF_HOST].len++; 2246 | break; 2247 | 2248 | case s_http_host_v6: 2249 | if (s != s_http_host_v6) { 2250 | u->field_data[UF_HOST].off = p - buf; 2251 | } 2252 | u->field_data[UF_HOST].len++; 2253 | break; 2254 | 2255 | case s_http_host_port: 2256 | if (s != s_http_host_port) { 2257 | u->field_data[UF_PORT].off = p - buf; 2258 | u->field_data[UF_PORT].len = 0; 2259 | u->field_set |= (1 << UF_PORT); 2260 | } 2261 | u->field_data[UF_PORT].len++; 2262 | break; 2263 | 2264 | case s_http_userinfo: 2265 | if (s != s_http_userinfo) { 2266 | u->field_data[UF_USERINFO].off = p - buf ; 2267 | u->field_data[UF_USERINFO].len = 0; 2268 | u->field_set |= (1 << UF_USERINFO); 2269 | } 2270 | u->field_data[UF_USERINFO].len++; 2271 | break; 2272 | 2273 | default: 2274 | break; 2275 | } 2276 | s = new_s; 2277 | } 2278 | 2279 | /* Make sure we don't end somewhere unexpected */ 2280 | switch (s) { 2281 | case s_http_host_start: 2282 | case s_http_host_v6_start: 2283 | case s_http_host_v6: 2284 | case s_http_host_port_start: 2285 | case s_http_userinfo: 2286 | case s_http_userinfo_start: 2287 | return 1; 2288 | default: 2289 | break; 2290 | } 2291 | 2292 | return 0; 2293 | } 2294 | 2295 | int 2296 | http_parser_parse_url(const char *buf, size_t buflen, int is_connect, 2297 | struct http_parser_url *u) 2298 | { 2299 | enum state s; 2300 | const char *p; 2301 | enum http_parser_url_fields uf, old_uf; 2302 | int found_at = 0; 2303 | 2304 | u->port = u->field_set = 0; 2305 | s = is_connect ? s_req_server_start : s_req_spaces_before_url; 2306 | old_uf = UF_MAX; 2307 | 2308 | for (p = buf; p < buf + buflen; p++) { 2309 | s = parse_url_char(s, *p); 2310 | 2311 | /* Figure out the next field that we're operating on */ 2312 | switch (s) { 2313 | case s_dead: 2314 | return 1; 2315 | 2316 | /* Skip delimeters */ 2317 | case s_req_schema_slash: 2318 | case s_req_schema_slash_slash: 2319 | case s_req_server_start: 2320 | case s_req_query_string_start: 2321 | case s_req_fragment_start: 2322 | continue; 2323 | 2324 | case s_req_schema: 2325 | uf = UF_SCHEMA; 2326 | break; 2327 | 2328 | case s_req_server_with_at: 2329 | found_at = 1; 2330 | 2331 | /* FALLTROUGH */ 2332 | case s_req_server: 2333 | uf = UF_HOST; 2334 | break; 2335 | 2336 | case s_req_path: 2337 | uf = UF_PATH; 2338 | break; 2339 | 2340 | case s_req_query_string: 2341 | uf = UF_QUERY; 2342 | break; 2343 | 2344 | case s_req_fragment: 2345 | uf = UF_FRAGMENT; 2346 | break; 2347 | 2348 | default: 2349 | assert(!"Unexpected state"); 2350 | return 1; 2351 | } 2352 | 2353 | /* Nothing's changed; soldier on */ 2354 | if (uf == old_uf) { 2355 | u->field_data[uf].len++; 2356 | continue; 2357 | } 2358 | 2359 | u->field_data[uf].off = p - buf; 2360 | u->field_data[uf].len = 1; 2361 | 2362 | u->field_set |= (1 << uf); 2363 | old_uf = uf; 2364 | } 2365 | 2366 | /* host must be present if there is a schema */ 2367 | /* parsing http:///toto will fail */ 2368 | if ((u->field_set & ((1 << UF_SCHEMA) | (1 << UF_HOST))) != 0) { 2369 | if (http_parse_host(buf, u, found_at) != 0) { 2370 | return 1; 2371 | } 2372 | } 2373 | 2374 | /* CONNECT requests can only contain "hostname:port" */ 2375 | if (is_connect && u->field_set != ((1 << UF_HOST)|(1 << UF_PORT))) { 2376 | return 1; 2377 | } 2378 | 2379 | if (u->field_set & (1 << UF_PORT)) { 2380 | /* Don't bother with endp; we've already validated the string */ 2381 | unsigned long v = strtoul(buf + u->field_data[UF_PORT].off, NULL, 10); 2382 | 2383 | /* Ports have a max value of 2^16 */ 2384 | if (v > 0xffff) { 2385 | return 1; 2386 | } 2387 | 2388 | u->port = (uint16_t) v; 2389 | } 2390 | 2391 | return 0; 2392 | } 2393 | 2394 | void 2395 | http_parser_pause(http_parser *parser, int paused) { 2396 | /* Users should only be pausing/unpausing a parser that is not in an error 2397 | * state. In non-debug builds, there's not much that we can do about this 2398 | * other than ignore it. 2399 | */ 2400 | if (HTTP_PARSER_ERRNO(parser) == HPE_OK || 2401 | HTTP_PARSER_ERRNO(parser) == HPE_PAUSED) { 2402 | SET_ERRNO((paused) ? HPE_PAUSED : HPE_OK); 2403 | } else { 2404 | assert(0 && "Attempting to pause parser in error state"); 2405 | } 2406 | } 2407 | 2408 | int 2409 | http_body_is_final(const struct http_parser *parser) { 2410 | return parser->state == s_message_done; 2411 | } 2412 | 2413 | unsigned long 2414 | http_parser_version(void) { 2415 | return HTTP_PARSER_VERSION_MAJOR * 0x10000 | 2416 | HTTP_PARSER_VERSION_MINOR * 0x00100 | 2417 | HTTP_PARSER_VERSION_PATCH * 0x00001; 2418 | } 2419 | --------------------------------------------------------------------------------