1 /*
2  * %CopyrightBegin%
3  *
4  * Copyright Ericsson AB 2008-2018. All Rights Reserved.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *
18  * %CopyrightEnd%
19  */
20 
21 /* A protocol decoder. Simple packet length extraction as well as packet
22  * body parsing with protocol specific callback interfaces (http and ssl).
23  *
24  * Code ripped out from inet_drv.c to also be used by BIF decode_packet.
25  */
26 #ifdef HAVE_CONFIG_H
27 #   include "config.h"
28 #endif
29 
30 #include "packet_parser.h"
31 
32 #include <ctype.h>
33 #include "sys.h"
34 
35 /* #define INET_DRV_DEBUG 1 */
36 #ifdef INET_DRV_DEBUG
37 #   define DEBUG 1
38 #   undef DEBUGF
39 #   define DEBUGF(X) printf X
40 #endif
41 
42 #if !defined(__WIN32__) && !defined(HAVE_STRNCASECMP)
43 #define STRNCASECMP my_strncasecmp
44 
my_strncasecmp(const char * s1,const char * s2,size_t n)45 static int my_strncasecmp(const char *s1, const char *s2, size_t n)
46 {
47     int i;
48 
49     for (i=0;i<n-1 && s1[i] && s2[i] && toupper(s1[i]) == toupper(s2[i]);++i)
50 	;
51     return (toupper(s1[i]) - toupper(s2[i]));
52 }
53 
54 
55 #else
56 #define  STRNCASECMP strncasecmp
57 #endif
58 
59 
60 #define HTTP_HDR_HASH_SIZE  53
61 #define HTTP_METH_HASH_SIZE 13
62 #define HTTP_MAX_NAME_LEN 50
63 
64 static char tspecial[128];
65 
66 static const char* http_hdr_strings[] = {
67     "Cache-Control",
68     "Connection",
69     "Date",
70     "Pragma",
71     "Transfer-Encoding",
72     "Upgrade",
73     "Via",
74     "Accept",
75     "Accept-Charset",
76     "Accept-Encoding",
77     "Accept-Language",
78     "Authorization",
79     "From",
80     "Host",
81     "If-Modified-Since",
82     "If-Match",
83     "If-None-Match",
84     "If-Range",
85     "If-Unmodified-Since",
86     "Max-Forwards",
87     "Proxy-Authorization",
88     "Range",
89     "Referer",
90     "User-Agent",
91     "Age",
92     "Location",
93     "Proxy-Authenticate",
94     "Public",
95     "Retry-After",
96     "Server",
97     "Vary",
98     "Warning",
99     "Www-Authenticate",
100     "Allow",
101     "Content-Base",
102     "Content-Encoding",
103     "Content-Language",
104     "Content-Length",
105     "Content-Location",
106     "Content-Md5",
107     "Content-Range",
108     "Content-Type",
109     "Etag",
110     "Expires",
111     "Last-Modified",
112     "Accept-Ranges",
113     "Set-Cookie",
114     "Set-Cookie2",
115     "X-Forwarded-For",
116     "Cookie",
117     "Keep-Alive",
118     "Proxy-Connection",
119     NULL
120 };
121 
122 
123 static const char* http_meth_strings[] = {
124     "OPTIONS",
125     "GET",
126     "HEAD",
127     "POST",
128     "PUT",
129     "DELETE",
130     "TRACE",
131     NULL
132 };
133 
134 static http_atom_t http_hdr_table[sizeof(http_hdr_strings)/sizeof(char*)];
135 static http_atom_t http_meth_table[sizeof(http_meth_strings)/sizeof(char*)];
136 
137 static http_atom_t* http_hdr_hash[HTTP_HDR_HASH_SIZE];
138 static http_atom_t* http_meth_hash[HTTP_METH_HASH_SIZE];
139 
140 #define CRNL(ptr) (((ptr)[0] == '\r') && ((ptr)[1] == '\n'))
141 #define NL(ptr)   ((ptr)[0] == '\n')
142 #define SP(ptr)   (((ptr)[0] == ' ') || ((ptr)[0] == '\t'))
143 #define is_tspecial(x) ((((x) > 32) && ((x) < 128)) ? tspecial[(x)] : 1)
144 
145 #define hash_update(h,c) do { \
146         unsigned long __g; \
147         (h) = ((h) << 4) + (c); \
148         if ((__g = (h) & 0xf0000000)) { \
149             (h) ^= (__g >> 24); \
150             (h) ^= __g; \
151         } \
152     } while(0)
153 
http_hash_insert(const char * name,http_atom_t * entry,http_atom_t ** hash,int hsize)154 static void http_hash_insert(const char* name, http_atom_t* entry,
155                              http_atom_t** hash, int hsize)
156 {
157     unsigned long h = 0;
158     const unsigned char* ptr = (const unsigned char*) name;
159     int ix;
160     int len = 0;
161 
162     while (*ptr != '\0') {
163         hash_update(h, *ptr);
164         ptr++;
165         len++;
166     }
167     ix = h % hsize;
168 
169     entry->next = hash[ix];
170     entry->h    = h;
171     entry->name = name;
172     entry->len  = len;
173     entry->atom = driver_mk_atom((char*)name);
174 
175     hash[ix] = entry;
176 }
177 
178 
http_init(void)179 static int http_init(void)
180 {
181     int i;
182     unsigned char* ptr;
183 
184     for (i = 0; i < 33; i++)
185         tspecial[i] = 1;
186     for (i = 33; i < 127; i++)
187         tspecial[i] = 0;
188     for (ptr = (unsigned char*)"()<>@,;:\\\"/[]?={} \t"; *ptr != '\0'; ptr++)
189         tspecial[*ptr] = 1;
190 
191     for (i = 0; i < HTTP_HDR_HASH_SIZE; i++)
192         http_hdr_hash[i] = NULL;
193     for (i = 0; http_hdr_strings[i] != NULL; i++) {
194         ASSERT(sys_strlen(http_hdr_strings[i]) <= HTTP_MAX_NAME_LEN);
195         http_hdr_table[i].index = i;
196         http_hash_insert(http_hdr_strings[i],
197                          &http_hdr_table[i],
198                          http_hdr_hash, HTTP_HDR_HASH_SIZE);
199     }
200 
201     for (i = 0; i < HTTP_METH_HASH_SIZE; i++)
202         http_meth_hash[i] = NULL;
203     for (i = 0; http_meth_strings[i] != NULL; i++) {
204         http_meth_table[i].index = i;
205         http_hash_insert(http_meth_strings[i],
206                          &http_meth_table[i],
207                          http_meth_hash, HTTP_METH_HASH_SIZE);
208     }
209     return 0;
210 }
211 
212 
213 #define CDR_MAGIC "GIOP"
214 
215 struct cdr_head {
216     unsigned char magic[4];        /* 4 bytes must be 'GIOP' */
217     unsigned char major;           /* major version */
218     unsigned char minor;           /* minor version */
219     unsigned char flags;           /* bit 0: 0 == big endian, 1 == little endian
220                                       bit 1: 1 == more fragments follow */
221     unsigned char message_type;    /* message type ... */
222     unsigned char message_size[4]; /* size in (flags bit 0 byte order) */
223 };
224 
225 #define TPKT_VRSN 3
226 
227 struct tpkt_head {
228     unsigned char vrsn;             /* contains TPKT_VRSN */
229     unsigned char reserved;
230     unsigned char packet_length[2]; /* size incl header, big-endian (?) */
231 };
232 
packet_parser_init()233 void packet_parser_init()
234 {
235     static int done = 0;
236     if (!done) {
237         done = 1;
238         http_init();
239     }
240 }
241 
242 /* Return > 0 Total packet length.in bytes
243  *        = 0 Length unknown, need more data.
244  *        < 0 Error, invalid format.
245  */
packet_get_length(enum PacketParseType htype,const char * ptr,unsigned n,unsigned max_plen,unsigned trunc_len,char delimiter,int * statep)246 int packet_get_length(enum PacketParseType htype,
247                       const char* ptr, unsigned n, /* Bytes read so far */
248                       unsigned max_plen,     /* Max packet length, 0=no limit */
249                       unsigned trunc_len,    /* Truncate (lines) if longer, 0=no limit */
250                       char     delimiter,    /* Line delimiting character */
251                       int*     statep)       /* Protocol specific state */
252 {
253     unsigned hlen, plen;
254 
255     switch (htype) {
256     case TCP_PB_RAW:
257         if (n == 0) goto more;
258         else {
259             DEBUGF((" => nothing remain packet=%d\r\n", n));
260             return n;
261         }
262 
263     case TCP_PB_1:
264         /* TCP_PB_1:    [L0 | Data] */
265         hlen = 1;
266         if (n < hlen) goto more;
267         plen = get_int8(ptr);
268         goto remain;
269 
270     case TCP_PB_2:
271         /* TCP_PB_2:    [L1,L0 | Data] */
272         hlen = 2;
273         if (n < hlen) goto more;
274         plen = get_int16(ptr);
275         goto remain;
276 
277     case TCP_PB_4:
278         /* TCP_PB_4:    [L3,L2,L1,L0 | Data] */
279         hlen = 4;
280         if (n < hlen) goto more;
281         plen = get_int32(ptr);
282         goto remain;
283 
284     case TCP_PB_RM:
285         /* TCP_PB_RM:    [L3,L2,L1,L0 | Data]
286         ** where MSB (bit) is used to signal end of record
287         */
288         hlen = 4;
289         if (n < hlen) goto more;
290         plen = get_int32(ptr) & 0x7fffffff;
291         goto remain;
292 
293     case TCP_PB_LINE_LF: {
294         /* TCP_PB_LINE_LF:  [Data ... Delimiter]  */
295         const char* ptr2;
296         if ((ptr2 = memchr(ptr, delimiter, n)) == NULL) {
297             if (n > max_plen && max_plen != 0) { /* packet full */
298                 DEBUGF((" => packet full (no NL)=%d\r\n", n));
299                 goto error;
300             }
301             else if (n >= trunc_len && trunc_len!=0) { /* buffer full */
302                 DEBUGF((" => line buffer full (no NL)=%d\r\n", n));
303                 return trunc_len;
304             }
305             goto more;
306         }
307         else {
308             int len = (ptr2 - ptr) + 1; /* including newline */
309             if (len > max_plen && max_plen!=0) {
310                 DEBUGF((" => packet_size %d exceeded\r\n", max_plen));
311                 goto error;
312             }
313             if (len > trunc_len && trunc_len!=0) {
314                 DEBUGF((" => truncated line=%d\r\n", trunc_len));
315                 return trunc_len;
316             }
317             DEBUGF((" => nothing remain packet=%d\r\n", len));
318             return len;
319         }
320     }
321 
322     case TCP_PB_ASN1: {
323         /* TCP_PB_ASN1: handles long (4 bytes) or short length format */
324         const char* tptr = ptr;
325         int length;
326         int nn = n;
327 
328         if (n < 2) goto more;
329         nn--;
330         if ((*tptr++ & 0x1f) == 0x1f) { /* Long tag format */
331             while (nn && ((*tptr & 0x80) == 0x80)) {
332                 tptr++;
333                 nn--;
334             }
335             if (nn < 2) goto more;
336             tptr++;
337             nn--;
338         }
339 
340         /* tptr now point to length field and nn characters remain */
341         length = *tptr & 0x7f;
342         if ((*tptr & 0x80) == 0x80) {   /* Long length format */
343             tptr++;
344             nn--;
345             if (nn < length) goto more;
346             switch (length) {
347             case 0: plen = 0; break;
348             case 1: plen = get_int8(tptr);  tptr += 1; break;
349             case 2: plen = get_int16(tptr); tptr += 2; break;
350             case 3: plen = get_int24(tptr); tptr += 3; break;
351             case 4: plen = get_int32(tptr); tptr += 4; break;
352             default: goto error; /* error */
353             }
354         }
355         else {
356             tptr++;
357             plen = length;
358         }
359         hlen = (tptr-ptr);
360         goto remain;
361     }
362 
363     case TCP_PB_CDR: {
364         const struct cdr_head* hp;
365         hlen = sizeof(struct cdr_head);
366         if (n < hlen) goto more;
367         hp = (struct cdr_head*) ptr;
368         if (sys_memcmp(hp->magic, CDR_MAGIC, 4) != 0)
369             goto error;
370         if (hp->flags & 0x01) /* Byte ordering flag */
371             plen = get_little_int32(hp->message_size);
372         else
373             plen = get_int32(hp->message_size);
374         goto remain;
375     }
376 
377     case TCP_PB_FCGI: {
378         const struct fcgi_head* hp;
379         hlen = sizeof(struct fcgi_head);
380         if (n < hlen) goto more;
381         hp = (struct fcgi_head*) ptr;
382         if (hp->version != FCGI_VERSION_1)
383                 goto error;
384         plen = ((hp->contentLengthB1 << 8) | hp->contentLengthB0)
385                + hp->paddingLength;
386         goto remain;
387     }
388     case TCP_PB_HTTPH:
389     case TCP_PB_HTTPH_BIN:
390         *statep = !0;
391     case TCP_PB_HTTP:
392     case TCP_PB_HTTP_BIN:
393         /* TCP_PB_HTTP:  data \r\n(SP data\r\n)*  */
394         plen = n;
395         if (((plen == 1) && NL(ptr)) || ((plen == 2) && CRNL(ptr)))
396             goto done;
397         else {
398             const char* ptr1 = ptr;
399             int   len = plen;
400 
401 	    if (!max_plen) {
402 		/* This is for backward compatibility with old user of decode_packet
403 		 * that might use option 'line_length' to limit accepted length of
404 		 * http lines.
405 		 */
406 		max_plen = trunc_len;
407 	    }
408 
409             while (1) {
410                 const char* ptr2 = memchr(ptr1, '\n', len);
411 
412                 if (ptr2 == NULL) {
413                     if (max_plen != 0) {
414                         if (n >= max_plen) /* packet full */
415                             goto error;
416                     }
417                     goto more;
418                 }
419                 else {
420                     plen = (ptr2 - ptr) + 1;
421 
422                     if (*statep == 0) {
423                         if (max_plen != 0 && plen > max_plen)
424                             goto error;
425                         goto done;
426                     }
427 
428                     if (plen < n) {
429                         if (SP(ptr2+1) && plen>2) {
430                             /* header field value continue on next line */
431                             ptr1 = ptr2+1;
432                             len = n - plen;
433                         }
434                         else {
435                             if (max_plen != 0 && plen > max_plen)
436                                 goto error;
437                             goto done;
438                         }
439                     }
440                     else {
441                         if (max_plen != 0 && plen > max_plen)
442                             goto error;
443                         goto more;
444                     }
445                 }
446             }
447         }
448     case TCP_PB_TPKT: {
449         const struct tpkt_head* hp;
450         hlen = sizeof(struct tpkt_head);
451         if (n < hlen)
452             goto more;
453         hp = (struct tpkt_head*) ptr;
454         if (hp->vrsn == TPKT_VRSN) {
455             plen = get_int16(hp->packet_length) - hlen;
456         } else {
457             goto error;
458 	}
459         goto remain;
460     }
461 
462     case TCP_PB_SSL_TLS:
463         hlen = 5;
464         if (n < hlen) goto more;
465         if ((ptr[0] & 0x80) && ptr[2] == 1) {
466             /* Ssl-v2 Client hello <<1:1, Len:15, 1:8, Version:16>>  */
467             plen = (get_int16(&ptr[0]) & 0x7fff) - 3;
468         }
469         else {
470             /* <<ContentType:8, Version:16, Length:16>> */
471             plen = get_int16(&ptr[3]);
472         }
473         goto remain;
474 
475     default:
476         DEBUGF((" => case error\r\n"));
477         return -1;
478     }
479 
480 more:
481     return 0;
482 
483 remain:
484     {
485         int tlen = hlen + plen;
486 	if ((max_plen != 0 && plen > max_plen)
487 	    || tlen < (int)hlen) { /* wrap-around protection */
488 	    return -1;
489 	}
490 	return tlen;
491     }
492 
493 done:
494     return plen;
495 
496 error:
497     return -1;
498 }
499 
500 
http_hash_lookup(const char * name,int len,unsigned long h,http_atom_t ** hash,int hsize)501 static http_atom_t* http_hash_lookup(const char* name, int len,
502                                      unsigned long h,
503                                      http_atom_t** hash, int hsize)
504 {
505     int ix = h % hsize;
506     http_atom_t* ap = hash[ix];
507 
508     while (ap != NULL) {
509         if ((ap->h == h) && (ap->len == len) &&
510             (sys_strncmp(ap->name, name, len) == 0))
511             return ap;
512         ap = ap->next;
513     }
514     return NULL;
515 }
516 
517 static void
http_parse_absoluteURI(PacketHttpURI * uri,const char * uri_ptr,int uri_len)518 http_parse_absoluteURI(PacketHttpURI* uri, const char* uri_ptr, int uri_len)
519 {
520     const char* p;
521 
522     if ((p = memchr(uri_ptr, '/', uri_len)) == NULL) {
523         /* host [":" port] */
524         uri->s2_ptr = "/";
525         uri->s2_len = 1;
526     }
527     else {
528         int n = (p - uri_ptr);
529         uri->s2_ptr = p;
530         uri->s2_len = uri_len - n;
531         uri_len = n;
532     }
533 
534     uri->s1_ptr = uri_ptr;
535     uri->port = 0; /* undefined */
536     /* host[:port]  */
537     if ((p = memchr(uri_ptr, ':', uri_len)) == NULL) {
538         uri->s1_len = uri_len;
539     }
540     else {
541         int n = (p - uri_ptr);
542         int port = 0;
543         uri->s1_len = n;
544         n = uri_len - (n+1);
545         p++;
546         while(n && isdigit((int) *p)) {
547             port = port*10 + (*p - '0');
548             n--;
549             p++;
550         }
551         if (n==0 && port!=0)
552             uri->port = port;
553   }
554 }
555 
556 /*
557 ** Handle URI syntax:
558 **
559 **  Request-URI    = "*" | absoluteURI | abs_path
560 **  absoluteURI    = scheme ":" *( uchar | reserved )
561 **  net_path       = "//" net_loc [ abs_path ]
562 **  abs_path       = "/" rel_path
563 **  rel_path       = [ path ] [ ";" params ] [ "?" query ]
564 **  path           = fsegment *( "/" segment )
565 **  fsegment       = 1*pchar
566 **  segment        = *pchar
567 **  params         = param *( ";" param )
568 **  param          = *( pchar | "/" )
569 **  query          = *( uchar | reserved )
570 **
571 **  http_URL       = "http:" "//" host [ ":" port ] [ abs_path ]
572 **
573 **  host           = <A legal Internet host domain name
574 **                   or IP address (in dotted-decimal form),
575 **                   as defined by Section 2.1 of RFC 1123>
576 **  port           = *DIGIT
577 **
578 **  {absoluteURI, <scheme>, <host>, <port>, <path+params+query>}
579 **       when <scheme> = http | https
580 **  {scheme, <scheme>, <chars>}
581 **       wheb <scheme> is something else then http or https
582 **  {abs_path,  <path>}
583 **
584 **  <string>  (unknown form)
585 **
586 */
http_parse_uri(PacketHttpURI * uri,const char * uri_ptr,int uri_len)587 static void http_parse_uri(PacketHttpURI* uri, const char* uri_ptr, int uri_len)
588 {
589     if ((uri_len == 1) && (uri_ptr[0] == '*'))
590         uri->type = URI_STAR;
591     else if ((uri_len <= 1) || (uri_ptr[0] == '/')) {
592         uri->type = URI_ABS_PATH;
593         uri->s1_ptr = uri_ptr;
594         uri->s1_len = uri_len;
595     }
596     else if ((uri_len>=7) && (STRNCASECMP(uri_ptr, "http://", 7) == 0)) {
597         uri_len -= 7;
598         uri_ptr += 7;
599         uri->type = URI_HTTP;
600         http_parse_absoluteURI(uri, uri_ptr, uri_len);
601     }
602     else if ((uri_len>=8) && (STRNCASECMP(uri_ptr, "https://", 8) == 0)) {
603         uri_len -= 8;
604         uri_ptr += 8;
605         uri->type = URI_HTTPS;
606         http_parse_absoluteURI(uri, uri_ptr, uri_len);
607     }
608     else {
609         char* ptr;
610         if ((ptr = memchr(uri_ptr, ':', uri_len)) == NULL) {
611             uri->type = URI_STRING;
612             uri->s1_ptr = uri_ptr;
613             uri->s1_len = uri_len;
614         }
615         else {
616             int slen = ptr - uri_ptr;
617             uri->type = URI_SCHEME;
618             uri->s1_ptr = uri_ptr;
619             uri->s1_len = slen;
620             uri->s2_ptr = uri_ptr + (slen+1);
621             uri->s2_len = uri_len - (slen+1);
622         }
623     }
624 }
625 
626 /*
627 ** parse http message:
628 **  http_eoh                          - end of headers
629 **  {http_header,   Key, Value}       - Key = atom() | string()
630 **  {http_request,  Method,Url,Version}
631 **  {http_response, Version, Status, Message}
632 **  {http_error,    Error-Line}
633 */
packet_parse_http(const char * buf,int len,int * statep,PacketCallbacks * pcb,void * arg)634 int packet_parse_http(const char* buf, int len, int* statep,
635                       PacketCallbacks* pcb, void* arg)
636 {
637     const char* ptr = buf;
638     const char* p0;
639     int n = len;
640 
641     /* remove trailing CRNL (accept NL as well) */
642     if ((n >= 2) && (buf[n-2] == '\r'))
643         n -= 2;
644     else if ((n >= 1) && (buf[n-1] == '\n'))
645         n -= 1;
646 
647     if (*statep == 0) {
648         /* start-line = Request-Line | Status-Line */
649 
650         if (n >= 5 && (sys_strncmp(buf, "HTTP/", 5) == 0)) {
651             int major  = 0;
652             int minor  = 0;
653             int status = 0;
654             /* Status-Line = HTTP-Version SP
655              *              Status-Code SP Reason-Phrase
656              *              CRNL
657              * HTTP-Version   = "HTTP" "/" 1*DIGIT "." 1*DIGIT
658              */
659             ptr += 5;
660             n -= 5;
661             p0 = ptr;
662             while (n && isdigit((int) *ptr)) {
663                 major = 10*major + (*ptr - '0');
664                 ptr++;
665                 n--;
666             }
667             if (ptr==p0 || !n || (*ptr != '.'))
668                 return -1;
669             ptr++;
670             n--;
671             p0 = ptr;
672             while (n && isdigit((int) *ptr)) {
673                 minor = 10*minor + (*ptr - '0');
674                 ptr++;
675                 n--;
676             }
677             if (ptr==p0) return -1;
678             p0 = ptr;
679             while (n && SP(ptr)) {
680                 ptr++; n--;
681             }
682             if (ptr==p0) return -1;
683 
684             while (n && isdigit((int) *ptr)) {
685                 status = 10*status + (*ptr - '0');
686                 ptr++;
687                 n--;
688             }
689             p0 = ptr;
690             while (n && SP(ptr)) {
691                 ptr++; n--;
692             }
693             if (ptr==p0 && n>0) return -1;
694 
695             /* NOTE: the syntax allows empty reason phrases */
696             (*statep) = !0;
697 
698             return pcb->http_response(arg, major, minor, status,
699                                       ptr, n);
700         }
701         else {
702             /* Request-Line = Method SP Request-URI SP HTTP-Version CRLF */
703             http_atom_t* meth;
704             const char* meth_ptr = buf;
705             int         meth_len;
706             PacketHttpURI uri;
707             const char*   uri_ptr;
708             int           uri_len;
709             int major  = 0;
710             int minor  = 0;
711             unsigned long h = 0;
712 
713             while (n && !is_tspecial((unsigned char)*ptr)) {
714                 hash_update(h, (int)*ptr);
715                 ptr++;
716                 n--;
717             }
718             meth_len = ptr - meth_ptr;
719             if (n == 0 || meth_len == 0 || !SP(ptr)) return -1;
720 
721             meth = http_hash_lookup(meth_ptr, meth_len, h,
722                                     http_meth_hash, HTTP_METH_HASH_SIZE);
723 
724             while (n && SP(ptr)) {
725                 ptr++; n--;
726             }
727             uri_ptr = ptr;
728             while (n && !SP(ptr)) {
729                 ptr++; n--;
730             }
731             if ((uri_len = (ptr - uri_ptr)) == 0)
732                 return -1;
733             while (n && SP(ptr)) {
734                 ptr++; n--;
735             }
736             if (n == 0) {
737                 (*statep) = !0;
738                 http_parse_uri(&uri, uri_ptr, uri_len);
739                 return pcb->http_request(arg, meth, meth_ptr, meth_len,
740                                          &uri, 0, 9);
741             }
742             if (n < 8)
743                 return -1;
744             if (sys_strncmp(ptr, "HTTP/", 5) != 0)
745                 return -1;
746             ptr += 5;
747             n   -= 5;
748 
749             p0 = ptr;
750             while (n && isdigit((int) *ptr)) {
751                 major = 10*major + (*ptr - '0');
752                 ptr++;
753                 n--;
754             }
755             if (ptr==p0 || !n || (*ptr != '.'))
756                 return -1;
757             ptr++;
758             n--;
759             p0 = ptr;
760             while (n && isdigit((int) *ptr)) {
761                 minor = 10*minor + (*ptr - '0');
762                 ptr++;
763                 n--;
764             }
765             if (ptr==p0) return -1;
766 
767             (*statep) = !0;
768             http_parse_uri(&uri, uri_ptr, uri_len);
769             return pcb->http_request(arg, meth, meth_ptr, meth_len,
770                                      &uri, major, minor);
771         }
772     }
773     else {
774         int up = 1;      /* make next char uppercase */
775         http_atom_t* name;
776         char name_buf[HTTP_MAX_NAME_LEN];
777         const char* name_ptr = name_buf;
778         int  name_len;
779         unsigned long h;
780 
781         if (n == 0) {
782             /* end of headers */
783             *statep = 0;  /* reset state (for next request) */
784             return pcb->http_eoh(arg);
785         }
786         h = 0;
787         name_len = 0;
788         while (!is_tspecial((unsigned char)*ptr)) {
789             if (name_len < HTTP_MAX_NAME_LEN) {
790                 int c = *ptr;
791                 if (up) {
792                     if (islower(c)) {
793                         c = toupper(c);
794                     }
795                     up = 0;
796                 }
797                 else {
798                     if (isupper(c))
799                         c = tolower(c);
800                     else if (c == '-')
801                         up = 1;
802                 }
803                 name_buf[name_len] = c;
804                 hash_update(h, c);
805             }
806             name_len++;
807             ptr++;
808             if (--n == 0) return -1;
809         }
810         if (*ptr != ':') {
811             return -1;
812         }
813         if (name_len <= HTTP_MAX_NAME_LEN) {
814             name = http_hash_lookup(name_buf, name_len, h,
815                                     http_hdr_hash, HTTP_HDR_HASH_SIZE);
816         }
817         else {
818             /* Is it ok to return original name without case adjustments? */
819             name_ptr = buf;
820             name = NULL;
821         }
822         ptr++;
823         n--;
824         /* Skip white space after ':' */
825         while (n && SP(ptr)) {
826             ptr++; n--;
827         }
828         return pcb->http_header(arg, name,
829                                 name_ptr, name_len,
830                                 buf, name_len,
831                                 ptr, n);
832     }
833     return -1;
834 }
835 
packet_parse_ssl(const char * buf,int len,PacketCallbacks * pcb,void * arg)836 int packet_parse_ssl(const char* buf, int len,
837                      PacketCallbacks* pcb, void* arg)
838 {
839     /* Check for ssl-v2 client hello */
840     if ((buf[0] & 0x80) && buf[2] == 1) {
841         unsigned major = (unsigned char) buf[3];
842         unsigned minor = (unsigned char) buf[4];
843         char prefix[4];
844         /* <<1:8,Length:24,Data/binary>> */
845         prefix[0] = 1;
846         put_int24(len-3,&prefix[1]);
847         return pcb->ssl_tls(arg, 22, major, minor, buf+3, len-3, prefix, sizeof(prefix));
848     }
849     else {
850         /* ContentType (1 byte), ProtocolVersion (2 bytes), Length (2 bytes big-endian) */
851         unsigned type  = (unsigned char) buf[0];
852         unsigned major = (unsigned char) buf[1];
853         unsigned minor = (unsigned char) buf[2];
854         return pcb->ssl_tls(arg, type, major, minor, buf+5, len-5, NULL, 0);
855     }
856 }
857 
858