Ver código fonte

- parse_uri tester

Andrei Pelinescu-Onciul 22 anos atrás
pai
commit
e082751bd4
1 arquivos alterados com 369 adições e 0 exclusões
  1. 369 0
      test/p_uri.c

+ 369 - 0
test/p_uri.c

@@ -0,0 +1,369 @@
+
+#include <stdio.h>
+#include <string.h>
+#include "../str.h"
+
+#define DBG printf
+#define LOG(lev, fmt, args...) printf(fmt, ## args)
+
+struct sip_uri {
+	str user;     /* Username */
+	str passwd;   /* Password */
+	str host;     /* Host name */
+	str port;     /* Port number */
+	str params;   /* Parameters */
+	str headers;  
+	unsigned short port_no;
+};
+
+
+
+int parse_uri(char* buf, int len, struct sip_uri* uri)
+{
+	enum states  {	URI_INIT, URI_USER, URI_PASSWORD, URI_HOST, URI_PORT,
+					URI_PARAM, URI_HEADERS };
+	enum states state;
+	char* s;
+	char* p;
+	char* end;
+	char* pass;
+	int found_user;
+	int error_headers;
+	
+#define still_at_user  \
+						if (found_user==0){ \
+							uri->user.s=uri->host.s; \
+							if (pass){\
+								uri->user.len=pass-uri->user.s; \
+								uri->passwd.s=pass+1; \
+								uri->passwd.len=p-uri->passwd.s; \
+								pass=0; \
+							}else{ \
+								uri->user.len=p-uri->user.s; \
+							}\
+							/* everything else is 0 */ \
+							uri->host.len=0; \
+							uri->port.s=0; \
+							uri->port.len=0; \
+							uri->params.s=0; \
+							uri->params.len=0; \
+							uri->headers.s=0; \
+							uri->headers.len=0; \
+							/* more zeroing */ \
+							s=p+1; \
+							found_user=1;\
+							error_headers=0; \
+							state=URI_HOST; \
+						}else goto error_bad_char; 
+	 
+	end=buf+len;
+	p=buf+4;
+	found_user=0;
+	error_headers=0;
+	pass=0;
+	state=URI_INIT;
+	memset(uri, 0, sizeof(struct sip_uri)); /* zero it all, just to be sure*/
+	/*look for sip:*/
+	if (len<4) goto error_too_short;
+	if (! ( ((buf[0]|0x20)=='s')&&((buf[1]|0x20)=='i')&&((buf[2]|0x20)=='p')&&
+		     (buf[3]==':') ) ) goto error_bad_uri;
+	
+	s=p;
+	state=URI_USER;
+	for(;p<end; p++){
+		switch(state){
+			case URI_USER:
+				switch(*p){
+					case '@':
+						/* found the user*/
+						uri->user.s=s;
+						uri->user.len=p-s;
+						state=URI_HOST;
+						found_user=1;
+						s=p+1; /* skip '@' */
+						break;
+					case ':':
+						/* found the user, or the host? */
+						uri->user.s=s;
+						uri->user.len=p-s;
+						state=URI_PASSWORD;
+						s=p+1; /* skip ':' */
+						break;
+					case ';':
+						/* this could be still the user or
+						 * params?*/
+						uri->host.s=s;
+						uri->host.len=p-s;
+						state=URI_PARAM;
+						s=p+1;
+						break;
+					case '?': /* still user or headers? */
+						uri->host.s=s;
+						uri->host.len=p-s;
+						state=URI_HEADERS;
+						s=p+1;
+						break;
+						/* almost anything permitted in the user part */
+				}
+				break;
+			case URI_PASSWORD: /* this can also be the port (missing user)*/
+				switch(*p){
+					case '@':
+						/* found the password*/
+						uri->passwd.s=s;
+						uri->passwd.len=p-s;
+						state=URI_HOST;
+						found_user=1;
+						s=p+1; /* skip '@' */
+						break;
+					case ';':
+						/* upps this is the port */
+						uri->port.s=s;
+						uri->port.len=p-s;
+						/* user contains in fact the host */
+						uri->host.s=uri->user.s;
+						uri->host.len=uri->user.len;
+						uri->user.s=0;
+						uri->user.len=0;
+						state=URI_PARAM;
+						found_user=1; /*  there is no user part */
+						s=p+1;
+						break;
+					case '?':
+						/* upps this is the port */
+						uri->port.s=s;
+						uri->port.len=p-s;
+						/* user contains in fact the host */
+						uri->host.s=uri->user.s;
+						uri->host.len=uri->user.len;
+						uri->user.s=0;
+						uri->user.len=0;
+						state=URI_HEADERS;
+						found_user=1; /*  there is no user part */
+						s=p+1;
+						break;
+					case ':':
+						goto error_bad_char;
+				}
+				break;
+			case URI_HOST:
+				switch(*p){
+					case ':':
+						/* found the host */
+						uri->host.s=s;
+						uri->host.len=p-s;
+						state=URI_PORT;
+						s=p+1;
+						break;
+					case ';':
+						uri->host.s=s;
+						uri->host.len=p-s;
+						state=URI_PARAM;
+						s=p+1;
+						break;
+					case '?':
+						uri->host.s=s;
+						uri->host.len=p-s;
+						state=URI_HEADERS;
+						s=p+1;
+						break;
+					case '&':
+					case '@':
+						goto error_bad_char;
+				}
+				break;
+			case URI_PORT:
+				switch(*p){
+					case ';':
+						uri->port.s=s;
+						uri->port.len=p-s;
+						state=URI_PARAM;
+						s=p+1;
+						break;
+					case '?':
+						uri->port.s=s;
+						uri->port.len=p-s;
+						state=URI_HEADERS;
+						s=p+1;
+						break;
+					case '&':
+					case '@':
+					case ':':
+						goto error_bad_char;
+				}
+				break;
+			case URI_PARAM:
+				/* supported params:
+				 *  maddr, transport, ttl, lr  */
+				switch(*p){
+					case '@':
+						/* ughhh, this is still the user */
+						still_at_user;
+						break;
+					case ';':
+						if (pass){
+							found_user=1; /* no user, pass cannot contain ';'*/
+							pass=0;
+						}
+						break;
+					case '?':
+						uri->params.s=s;
+						uri->params.len=p-s;
+						state=URI_HEADERS;
+						s=p+1;
+						if (pass){
+							found_user=1; /* no user, pass cannot contain '?'*/
+							pass=0;
+						}
+						break;
+					case ':':
+						if (found_user==0){
+							/*might be pass but only if user not found yet*/
+							if (pass){
+								found_user=1; /* no user */
+								pass=0;
+							}else{
+								pass=p;
+							}
+						}
+						break;
+				};
+				break;
+			case URI_HEADERS:
+				/* for now nobody needs them so we completely ignore the 
+				 * headers (they are not allowed in request uri) --andrei */
+				switch(*p){
+					case '@':
+						/* yak, we are still at user */
+						still_at_user;
+						break;
+					case ';':
+						/* we might be still parsing user, try it */
+						if (found_user) goto error_bad_char;
+						error_headers=1; /* if this is not the user
+											we have an error */
+						/* if pass is set => it cannot be user:pass
+						 * => error (';') is illegal in a header */
+						if (pass) goto error_headers;
+						break;
+					case ':':
+						if (found_user==0){
+							/*might be pass but only if user not found yet*/
+							if (pass){
+								found_user=1; /* no user */
+								pass=0;
+							}else{
+								pass=p;
+							}
+						}
+						break;
+					case '?':
+						if (pass){
+							found_user=1; /* no user, pass cannot conaint '?'*/
+							pass=0;
+						}
+						break;
+				}
+				break;
+			default:
+				goto error_bug;
+		}
+	}
+	/*end of uri */
+	switch (state){
+		case URI_USER:
+			/* this is the host, it can't be the user */
+			if (found_user) goto error_bad_uri;
+			uri->host.s=s;
+			uri->host.len=p-s;
+			state=URI_HOST;
+			break;
+		case URI_PASSWORD:
+			/* this is the port, it can't be the passwd */
+			if (found_user) goto error_bad_uri;
+			uri->port.s=s;
+			uri->port.len=p-s;
+			uri->host=uri->user;
+			uri->user.s=0;
+			uri->user.len=0;
+			break;
+		case URI_HOST:
+			uri->host.s=s;
+			uri->host.len=p-s;
+			break;
+		case URI_PORT:
+			uri->port.s=s;
+			uri->port.len=p-s;
+			break;
+		case URI_PARAM:
+			uri->params.s=s;
+			uri->params.len=p-s;
+			break;
+		case URI_HEADERS:
+			uri->headers.s=s;
+			uri->headers.len=p-s;
+			if (error_headers) goto error_headers;
+			break;
+		default:
+			goto error_bug;
+	}
+	
+	/* do stuff */
+	DBG("parsed uri:\n user=<%.*s>(%d)\n passwd=<%.*s>(%d)\n host=<%.*s>(%d)\n"
+			" port=<%.*s>(%d)\n params=<%.*s>(%d)\n headers=<%.*s>(%d)\n",
+			uri->user.len, uri->user.s, uri->user.len,
+			uri->passwd.len, uri->passwd.s, uri->passwd.len,
+			uri->host.len, uri->host.s, uri->host.len,
+			uri->port.len, uri->port.s, uri->port.len,
+			uri->params.len, uri->params.s, uri->params.len,
+			uri->headers.len, uri->headers.s, uri->headers.len
+		);
+	return 0;
+	
+error_too_short:
+	LOG(L_ERR, "ERROR: parse_uri: uri too short: <%.*s> (%d)\n",
+			len, buf, len);
+	return -1;
+error_bad_char:
+	LOG(L_ERR, "ERROR: parse_uri: bad char '%c' in state %d"
+			" parsed: <%.*s> (%d) / <%.*s> (%d)\n",
+			*p, state, (p-buf), buf, (p-buf), len, buf, len);
+	return -1;
+error_bad_uri:
+	LOG(L_ERR, "ERROR: parse_uri: bad uri,  state %d"
+			" parsed: <%.*s> (%d) / <%.*s> (%d)\n",
+			 state, (p-buf), buf, (p-buf), len, buf, len);
+	return -1;
+error_headers:
+	LOG(L_ERR, "ERROR: parse_uri: bad uri headers: <%.*s>(%d)"
+			" / <%.*s>(%d)\n",
+			uri->headers.len, uri->headers.s, uri->headers.len,
+			len, buf, len);
+	return -1;
+error_bug:
+	LOG(L_CRIT, "BUG: parse_uri: bad  state %d"
+			" parsed: <%.*s> (%d) / <%.*s> (%d)\n",
+			 state, (p-buf), buf, (p-buf), len, buf, len);
+	return -1;
+}
+
+
+
+int main (int argc, char** argv)
+{
+
+	int r;
+	struct sip_uri uri;
+
+	if (argc<2){
+		printf("usage:    %s  uri [, uri...]\n", argv[0]);
+		exit(1);
+	}
+	
+	for (r=1; r<argc; r++){
+		if (parse_uri(argv[r], strlen(argv[r]), &uri)<0){
+			printf("error: parsing %s\n", argv[r]);
+		}
+	}
+	return 0;
+}