Line data Source code
1 : #include "fd_url.h" 2 : 3 : fd_url_t * 4 : fd_url_parse_cstr( fd_url_t * const url, 5 : char const * const url_str, 6 : ulong const url_str_len, 7 0 : int * opt_err ) { 8 0 : int err_[1]; 9 0 : if( !opt_err ) opt_err = err_; 10 0 : *opt_err = FD_URL_SUCCESS; 11 : 12 0 : char const * const url_end = url_str+url_str_len; 13 : 14 0 : char const * const scheme = url_str; 15 0 : ulong scheme_len = 0UL; 16 0 : if( FD_UNLIKELY( url_str_len<8UL ) ) return NULL; 17 0 : if( fd_memeq( scheme, "http://", 7 ) ) { 18 0 : scheme_len = 7; 19 0 : } else if( fd_memeq( scheme, "https://", 8 ) ) { 20 0 : scheme_len = 8; 21 0 : } else { 22 0 : *opt_err = FD_URL_ERR_SCHEME; 23 0 : return NULL; 24 0 : } 25 : 26 0 : char const * const authority = scheme+scheme_len; 27 : 28 : /* Find beginning of path */ 29 0 : char const * authority_end; 30 0 : for( authority_end = authority; 31 0 : authority_end < url_end && *authority_end!='/'; 32 0 : authority_end++ ) { 33 0 : if( FD_UNLIKELY( *authority_end=='@' ) ) { 34 0 : *opt_err = FD_URL_ERR_USERINFO; 35 0 : return NULL; /* userinfo not supported */ 36 0 : } 37 0 : } 38 0 : ulong const authority_len = (ulong)( authority_end-authority ); 39 : 40 : /* Find port number */ 41 0 : char const * const host = authority; 42 0 : ulong host_len = authority_len; 43 0 : char const * port = NULL; 44 0 : ulong port_len = 0UL; 45 0 : for( ulong j=0UL; j<authority_len; j++ ) { 46 0 : if( authority[ j ]==':' ) { 47 0 : host_len = j; 48 0 : port = authority +j+1; 49 0 : port_len = authority_len-j-1; 50 0 : break; 51 0 : } 52 0 : } 53 : 54 0 : if( FD_UNLIKELY( host_len>255 ) ) { 55 0 : *opt_err = FD_URL_ERR_HOST_OVERSZ; 56 0 : return NULL; 57 0 : } 58 : 59 : 60 0 : *url = (fd_url_t){ 61 0 : .scheme = scheme, 62 0 : .scheme_len = scheme_len, 63 0 : .host = host, 64 0 : .host_len = host_len, 65 0 : .port = port, 66 0 : .port_len = port_len, 67 0 : .tail = authority+authority_len, 68 0 : .tail_len = (ulong)( url_end-(authority+authority_len) ) 69 0 : }; 70 : 71 0 : return url; 72 0 : } 73 : 74 : 75 : static inline int 76 0 : fd_hex_unhex( int c ) { 77 0 : if( c>='0' && c<='9' ) return c-'0'; 78 0 : if( c>='a' && c<='f' ) return c-'a'+0xa; 79 0 : if( c>='A' && c<='F' ) return c-'A'+0xa; 80 0 : return -1; 81 0 : } 82 : 83 : ulong 84 : fd_url_unescape( char * const msg, 85 12 : ulong const len ) { 86 12 : char * end = msg+len; 87 12 : int state = 0; 88 12 : char * dst = msg; 89 12 : for( char * src=msg; src<end; src++ ) { 90 : /* invariant: p<=msg */ 91 0 : switch( state ) { 92 0 : case 0: 93 0 : if( FD_LIKELY( (*src)!='%' ) ) { 94 0 : *dst = *src; 95 0 : dst++; 96 0 : } else { 97 0 : state = 1; 98 0 : } 99 0 : break; 100 0 : case 1: 101 0 : if( FD_LIKELY( (*src)!='%' ) ) { 102 0 : *dst = (char)( ( fd_hex_unhex( *src )&0xf )<<4 ); 103 0 : state = 2; 104 0 : } else { 105 : /* FIXME is 'aa%%aa' a valid escape? */ 106 0 : *(dst++) = '%'; 107 0 : state = 0; 108 0 : } 109 0 : break; 110 0 : case 2: 111 0 : *dst = (char)( (*dst) | ( fd_hex_unhex( *src )&0xf ) ); 112 0 : dst++; 113 0 : state = 0; 114 0 : break; 115 0 : } 116 0 : } 117 12 : return (ulong)( dst-msg ); 118 12 : }