1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 
3 /*  Monkey HTTP Server
4  *  ==================
5  *  Copyright 2001-2017 Eduardo Silva <eduardo@monkey.io>
6  *
7  *  Licensed under the Apache License, Version 2.0 (the "License");
8  *  you may not use this file except in compliance with the License.
9  *  You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  *  Unless required by applicable law or agreed to in writing, software
14  *  distributed under the License is distributed on an "AS IS" BASIS,
15  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  *  See the License for the specific language governing permissions and
17  *  limitations under the License.
18  */
19 
20 #ifndef MK_HTTP_PARSER_H
21 #define MK_HTTP_PARSER_H
22 
23 #define _GNU_SOURCE
24 #include <ctype.h>
25 
26 #include <monkey/mk_core.h>
27 #include <monkey/mk_http.h>
28 #include <monkey/mk_http_internal.h>
29 
30 /* General status */
31 #define MK_HTTP_PARSER_PENDING -10  /* cannot complete until more data arrives */
32 #define MK_HTTP_PARSER_ERROR    -1  /* found an error when parsing the string  */
33 #define MK_HTTP_PARSER_OK        0  /* parser OK, ready to go                  */
34 
extractPixmaps(const QIcon & icon)35 /* Connection header values */
36 #define MK_HTTP_PARSER_CONN_EMPTY    0
37 #define MK_HTTP_PARSER_CONN_UNKNOWN -1
38 #define MK_HTTP_PARSER_CONN_KA       1
39 #define MK_HTTP_PARSER_CONN_CLOSE    2
40 #define MK_HTTP_PARSER_CONN_UPGRADE  4
41 #define MK_HTTP_PARSER_CONN_HTTP2_SE 8
42 
43 /* Upgrades supported */
44 #define MK_HTTP_PARSER_UPGRADE_NONE  0
45 #define MK_HTTP_PARSER_UPGRADE_H2    1
46 #define MK_HTTP_PARSER_UPGRADE_H2C   2
47 
48 #define MK_HEADER_EXTRA_SIZE         8
49 
50 /* Request levels
51  * ==============
52  *
53  * 1. FIRST_LINE         : Method, URI (+ QS) + Protocol version + CRLF
54  * 2. HEADERS (optional) : KEY, SEP, VALUE + CRLF
55  * 3. BODY (option)      : data based on Content-Length or Chunked transfer encoding
56  */
57 
58 enum {
59     REQ_LEVEL_FIRST    = 1,
60     REQ_LEVEL_CONTINUE ,
61     REQ_LEVEL_HEADERS  ,
62     REQ_LEVEL_END      ,
63     REQ_LEVEL_BODY
64 };
65 
66 /* Statuses per levels */
67 enum {
68     /* REQ_LEVEL_FIRST */
icon(IconType type) const69     MK_ST_REQ_METHOD        = 1,
70     MK_ST_REQ_URI           ,
71     MK_ST_REQ_QUERY_STRING  ,
72     MK_ST_REQ_PROT_VERSION  ,
73     MK_ST_FIRST_CONTINUE    ,
74     MK_ST_FIRST_FINALIZING  ,    /* LEVEL_FIRST finalize the request */
75     MK_ST_FIRST_COMPLETE    ,
76 
77     /* REQ_HEADERS */
78     MK_ST_HEADER_KEY        ,
79     MK_ST_HEADER_SEP        ,
80     MK_ST_HEADER_VAL_STARTS ,
81     MK_ST_HEADER_VALUE      ,
82     MK_ST_HEADER_END        ,
83     MK_ST_BLOCK_END
84 };
85 
86 /* Known HTTP Methods */
87 enum mk_request_methods {
88     MK_METHOD_GET     = 0,
89     MK_METHOD_POST       ,
90     MK_METHOD_HEAD       ,
91     MK_METHOD_PUT        ,
92     MK_METHOD_DELETE     ,
93     MK_METHOD_OPTIONS    ,
94     MK_METHOD_SIZEOF     ,
95     MK_METHOD_UNKNOWN
96 };
97 
98 /*
99  * Define a list of known headers, they are used to perform headers
100  * lookups in the parser and further Monkey core.
101  */
102 enum mk_request_headers {
103     MK_HEADER_ACCEPT             = 0,
104     MK_HEADER_ACCEPT_CHARSET        ,
105     MK_HEADER_ACCEPT_ENCODING       ,
106     MK_HEADER_ACCEPT_LANGUAGE       ,
107     MK_HEADER_AUTHORIZATION         ,
108     MK_HEADER_CACHE_CONTROL         ,
109     MK_HEADER_COOKIE                ,
110     MK_HEADER_CONNECTION            ,
111     MK_HEADER_CONTENT_LENGTH        ,
112     MK_HEADER_CONTENT_RANGE         ,
113     MK_HEADER_CONTENT_TYPE          ,
114     MK_HEADER_HOST                  ,
115     MK_HEADER_HTTP2_SETTINGS        ,
116     MK_HEADER_IF_MODIFIED_SINCE     ,
117     MK_HEADER_LAST_MODIFIED         ,
118     MK_HEADER_LAST_MODIFIED_SINCE   ,
119     MK_HEADER_RANGE                 ,
120     MK_HEADER_REFERER               ,
121     MK_HEADER_UPGRADE               ,
122     MK_HEADER_USER_AGENT            ,
123     MK_HEADER_SIZEOF                ,
124 
125     /* used by the core for custom headers */
126     MK_HEADER_OTHER
127 };
128 
129 /*
130  * Expected Header values that are used to take logic
131  * decision.
132  */
133 #define MK_CONN_KEEP_ALIVE     "keep-alive"
134 #define MK_CONN_CLOSE          "close"
135 #define MK_CONN_UPGRADE        "upgrade"
136 
137 /* HTTP Upgrade options available */
138 #define MK_UPGRADE_H2          "h2"
139 #define MK_UPGRADE_H2C         "h2c"
140 
141 struct mk_http_header {
142     /* The header type/name, e.g: MK_HEADER_CONTENT_LENGTH */
143     int type;
144 
145     /* Reference the header Key name, e.g: 'Content-Lentth' */
146     mk_ptr_t key;
147 
148     /* Reference the header Value, e/g: '123456' */
149     mk_ptr_t val;
150 
151     /*
152      * Link to head list, it's used to reference this node and
153      * iterate it as a linked list
154      */
155     struct mk_list _head;
156 };
157 
158 /* This structure is the 'Parser Context' */
159 struct mk_http_parser {
160     int                        i;
161     int                        level;   /* request level */
162     int                        status;  /* level status  */
163     int                        next;    /* something next after status ? */
164     int                        length;
165     int                        method;
166 
167     /* lookup fields */
168     int                        start;
169     int                        end;
170     int                        chars;
171 
172     /* it stores the numeric value of Content-Length header */
173     int                        header_host_port;
174 
175     long int                   body_received;
176     long int                   header_content_length;
177 
178     /*
179      * connection header value discovered: it can be set with
180      * values:
181      *
182      * MK_HTTP_PARSER_CONN_EMPTY  : header not set
183      * MK_HTTP_PARSER_CONN_UNKNOWN: unexpected value
184      * MK_HTTP_PARSER_CONN_KA     : keep-alive
185      * MK_HTTP_PARSER_CONN_CLOSE  : close
186      */
187     int                        header_connection;
188 
189     /* upgrade request: we suppport the following values:
190      *
191      * MK_HTTP_PARSER_UPGRADE_H2  : HTTP/2.0 over TLS
192      * MK_HTTP_PARSER_UPGRADE_H2C : HTTP/2.0 (plain TCP)
193      */
194     int                        header_upgrade;
195 
196     /* probable current header, fly parsing */
197     int                        header_key;
198     int                        header_sep;
199     int                        header_val;
200     int                        header_min;
201     int                        header_max;
202     int                        headers_extra_count;
203 
204     /* Known headers */
205     struct mk_http_header      headers[MK_HEADER_SIZEOF];
206 
207     /* Head of linked list for all headers found in the request */
208     int                        header_count;
209     struct mk_list             header_list;
210 
211     /* Extra headers */
212     struct mk_http_header      headers_extra[MK_HEADER_EXTRA_SIZE];
213 };
214 
215 
216 #ifdef HTTP_STANDALONE
217 
218 /* ANSI Colors */
219 
220 #define ANSI_RESET "\033[0m"
221 #define ANSI_BOLD  "\033[1m"
222 
223 #define ANSI_CYAN          "\033[36m"
224 #define ANSI_BOLD_CYAN     ANSI_BOLD ANSI_CYAN
225 #define ANSI_MAGENTA       "\033[35m"
226 #define ANSI_BOLD_MAGENTA  ANSI_BOLD ANSI_MAGENTA
227 #define ANSI_RED           "\033[31m"
228 #define ANSI_BOLD_RED      ANSI_BOLD ANSI_RED
229 #define ANSI_YELLOW        "\033[33m"
230 #define ANSI_BOLD_YELLOW   ANSI_BOLD ANSI_YELLOW
231 #define ANSI_BLUE          "\033[34m"
232 #define ANSI_BOLD_BLUE     ANSI_BOLD ANSI_BLUE
233 #define ANSI_GREEN         "\033[32m"
234 #define ANSI_BOLD_GREEN    ANSI_BOLD ANSI_GREEN
235 #define ANSI_WHITE         "\033[37m"
236 #define ANSI_BOLD_WHITE    ANSI_BOLD ANSI_WHITE
237 
238 #define TEST_OK      0
239 #define TEST_FAIL    1
240 
241 
242 static inline void p_field(struct mk_http_parser *req, char *buffer)
243 {
244     int i;
245 
246     printf("'");
247     for (i = req->start; i < req->end; i++) {
248         printf("%c", buffer[i]);
249     }
250     printf("'");
251 
252 }
253 
254 static inline int eval_field(struct mk_http_parser *req, char *buffer)
255 {
256     if (req->level == REQ_LEVEL_FIRST) {
257         printf("[ \033[35mfirst level\033[0m ] ");
258     }
259     else {
260         printf("[   \033[36mheaders\033[0m   ] ");
261     }
262 
263     printf(" ");
264     switch (req->status) {
265     case MK_ST_REQ_METHOD:
266         printf("MK_ST_REQ_METHOD       : ");
267         break;
268     case MK_ST_REQ_URI:
269         printf("MK_ST_REQ_URI          : ");
270         break;
271     case MK_ST_REQ_QUERY_STRING:
272         printf("MK_ST_REQ_QUERY_STRING : ");
273         break;
274     case MK_ST_REQ_PROT_VERSION:
275         printf("MK_ST_REQ_PROT_VERSION : ");
276         break;
277     case MK_ST_HEADER_KEY:
278         printf("MK_ST_HEADER_KEY       : ");
279         break;
280     case MK_ST_HEADER_VAL_STARTS:
281         printf("MK_ST_HEADER_VAL_STARTS: ");
282         break;
283     case MK_ST_HEADER_VALUE:
284         printf("MK_ST_HEADER_VALUE     : ");
285         break;
286     case MK_ST_HEADER_END:
287         printf("MK_ST_HEADER_END       : ");
288         break;
289     default:
290         printf("\033[31mUNKNOWN STATUS (%i)\033[0m     : ", req->status);
291         break;
292     };
293 
294 
295     p_field(req, buffer);
296     printf("\n");
297 
298     return 0;
299 }
300 #endif /* HTTP_STANDALONE */
301 
302 #define mk_http_set_minor_version(c)                \
303     if (c == '1') {                                 \
304         req->protocol = MK_HTTP_PROTOCOL_11;        \
305     }                                               \
306     else if (c == '0') {                            \
307         req->protocol = MK_HTTP_PROTOCOL_10;        \
308     }                                               \
309     else {                                          \
310         req->protocol = MK_HTTP_PROTOCOL_UNKNOWN;   \
311     }
312 
313 
314 static inline void mk_http_parser_init(struct mk_http_parser *p)
315 {
316     memset(p, '\0', sizeof(struct mk_http_parser));
317 
318     p->level  = REQ_LEVEL_FIRST;
319     p->status = MK_ST_REQ_METHOD;
320     p->chars  = -1;
321     p->method = -1;
322 
323     /* init headers */
324     p->header_key = -1;
325     p->header_sep = -1;
326     p->header_val = -1;
327     p->header_min = -1;
328     p->header_max = -1;
329     p->header_content_length = -1;
330 
331     /* init list header */
332     p->header_count = 0;
333     mk_list_init(&p->header_list);
334 }
335 
336 static inline int mk_http_parser_more(struct mk_http_parser *p, int len)
337 {
338     if (abs(len - p->i) - 1 > 0) {
339         return MK_TRUE;
340     }
341 
342     return MK_FALSE;
343 }
344 
345 int mk_http_parser(struct mk_http_request *req, struct mk_http_parser *p,
346                    char *buffer, int buf_len, struct mk_server *server);
347 
348 #endif /* MK_HTTP_H */
349