浏览代码

Identity-info and Identity header parser does not insist on BNF specified
in RFC.

Memory allocator part of Identity-info, Identity and Date header moved out
from get_hdr_field()@parser/msg_parser.c

Gergely Kovacs 18 年之前
父节点
当前提交
d228f3d349
共有 3 个文件被更改,包括 223 次插入156 次删除
  1. 37 24
      parser/parse_date.c
  2. 87 79
      parser/parse_identity.c
  3. 99 53
      parser/parse_identityinfo.c

+ 37 - 24
parser/parse_date.c

@@ -1,5 +1,5 @@
 /*
- * $Id$ 
+ * $Id$
  *
  * Copyright (c) 2007 iptelorg GmbH
  *
@@ -140,46 +140,59 @@ static int rfc1123totm (char *stime, struct tm *ttm ) {
 	return 0;
 }
 
-char* parse_date(char *buffer, char *end, struct date_body *db)
+void parse_date(char *buffer, char *end, struct date_body *db)
 {
-	char *p;
-	int i1;
-
 	db->error=PARSE_ERROR;
-	p = buffer;
 
 	/* check whether enough characters are available */
-	for (i1 = 0; i1 < RFC1123DATELENGTH || p[i1] == '\n' || p + i1 >= end;i1++);
-	if (i1 < RFC1123DATELENGTH)
+	if (end - buffer < RFC1123DATELENGTH)
 		goto error;
 
 	if (rfc1123totm(buffer,&db->date))
 		goto error;
 
-	p+=RFC1123DATELENGTH;
+	db->error=PARSE_OK;
+	return ;
+error:
+	LOG(L_ERR,"ERROR: parse_date: parse error\n");
+	return ;
+}
 
-	p=eat_lws_end(p, end);
-	/*check if the header ends here*/
-	if (p>=end) {
-		LOG(L_ERR, "ERROR: parse_date: strange EoHF\n");
+int parse_date_header(struct sip_msg *msg)
+{
+	struct date_body* date_b;
+
+
+	if ( !msg->date && (parse_headers(msg,HDR_DATE_F,0)==-1 || !msg->date) ) {
+		LOG(L_ERR,"ERROR:parse_date_header: bad msg or missing DATE header\n");
 		goto error;
 	}
-	if (*p=='\r' && p+1<end && *(p+1)=='\n') {
-		db->error=PARSE_OK;
-		return p+2;
+
+	/* maybe the header is already parsed! */
+	if (msg->date->parsed)
+		return 0;
+
+	date_b=pkg_malloc(sizeof(*date_b));
+	if (date_b==0){
+		LOG(L_ERR, "ERROR:parse_date_header: out of memory\n");
+		goto error;
 	}
-	if (*p=='\n') {
-		db->error=PARSE_OK;
-		return p+1;
+	memset(date_b, 0, sizeof(*date_b));
+
+	parse_date(msg->date->body.s,
+			   msg->date->body.s + msg->date->body.len+1,
+			   date_b);
+	if (date_b->error==PARSE_ERROR){
+		free_date(date_b);
+		goto error;
 	}
-	LOG(L_ERR, "ERROR: Date EoL expected\n");
+	msg->date->parsed=(void*)date_b;
+
+	return 0;
 error:
-	LOG(L_ERR,"ERROR: parse_date: parse error: \"%.*s\" (%d)\n",
-				i1, buffer, i1);
-	return p;
+	return -1;
 }
 
-
 void free_date(struct date_body *db)
 {
 	pkg_free(db);

+ 87 - 79
parser/parse_identity.c

@@ -1,5 +1,5 @@
 /*
- * $Id$ 
+ * $Id$
  *
  * Copyright (c) 2007 iptelorg GmbH
  *
@@ -37,136 +37,144 @@
  * Parse Identity header field
  */
 
+#define SP(_c) ((_c)=='\t' || (_c)==' ')
+inline static int isendofhash (char* p, char* end)
+{
+	/* new header line */
+	if ((p<end && *p=='"')
+		/* end of message */
+		|| ((*p=='\n' || *p=='\r') && p+1==end))
+		return 1;
+	else
+		return 0;
+}
+
+
 /*
  * If the value of Identity header contains any LWS then we've to create
  * a new buffer and move there the LWSless part
  */
-int movetomybuffer (char *buffer, char *end, char *p, struct identity_body *ib)
+int movetomybuffer (char *pstart,
+					char *pend,
+					char *pcur,
+					struct identity_body *ib)
 {
-	char *bufend;
+	char *phashend;
 
-	if (!(bufend=q_memchr(p, '"', end-p))) {
-		LOG(L_ERR, "parse_identity: quotation mark is missing\n");
-		return -1;
-	}
+	for (phashend = pcur; !isendofhash(phashend, pend); phashend++);
 
-	if (!(ib->hash.s=pkg_malloc(bufend-buffer))) {
+	if (!(ib->hash.s=pkg_malloc(phashend-pstart))) {
 		LOG(L_ERR, "parse_identity: out of memory\n");
 		return -2;
 	}
 	ib->ballocated=1;
 
-	memcpy(ib->hash.s, buffer, ib->hash.len);
+	memcpy(ib->hash.s, pstart, ib->hash.len);
 
 	return 0;
 }
 
-char* parse_identity(char *buffer, char* end, struct identity_body* ib)
+
+void parse_identity(char *buffer, char* end, struct identity_body* ib)
 {
-	char *p=NULL;
-	char bpadded=0;
+	char *p=NULL, *pstart=NULL;
 
 	if (!buffer || !end || !ib)
 		goto error;
 
 	ib->error=PARSE_ERROR;
 
-	/* there must be '"' sign because there might be '=' sign in the
-	 * value of Identity header
-	 */
-	if (*buffer != '"') {
-		LOG(L_ERR, "parse_identity: quotation mark is missing\n");
-		goto error;
-	}
+	/* if there is a '"' sign then we'll step over it */
+	*buffer == '"' ? (pstart = buffer + 1) : (pstart = buffer);
 
-	/* we step over the '"' mark */
-	ib->hash.s=buffer+1;
+	ib->hash.s=pstart;
 	ib->hash.len=0;
 
-	for (p=buffer+1; p < end && *p != '"'; p++) {
+	for (p = pstart; p < end; p++) {
 		/* check the BASE64 alphabet */
-		if (!bpadded
-		    && ((*p >= 'a' && *p <='z')
-			 	|| (*p >= 'A' && *p <='Z')
-				|| (*p >= '0' && *p <='9')
-				|| (*p == '+' || *p == '/'))) {
+		if (((*p >= 'a' && *p <='z')
+			|| (*p >= 'A' && *p <='Z')
+			|| (*p >= '0' && *p <='9')
+			|| (*p == '+' || *p == '/' || *p == '='))) {
 			if (ib->ballocated)
 				ib->hash.s[ib->hash.len]=*p;
 			ib->hash.len++;
 			continue;
 		}
 
-		/* check the BASE64 padding */
-		if ((p+1 < end && *p == '=' && *(p+1) != '=')
-		    || (p+2 < end && *p == '=' && *(p+1) == '=' && *(p+2) != '=')) {
-			bpadded=1;
-			if (ib->ballocated)
-				ib->hash.s[ib->hash.len]=*p;
-			ib->hash.len++;
-			continue;
-		}
-
-		/* LSW case */
-		if (*p == ' ' || *p == '\t') {
-			for (p++; p < end && (*p == ' ' || *p == '\t'); p++);
-			if (p == end)
-				goto parseerror;
-			/* we've to create another whitespaceless buffer */
-			if (!ib->ballocated && (movetomybuffer(buffer+1, end, p-1, ib)))
+		/* LWS */
+		if (*p=='\n' && p+1<end && SP(*(p+1))) {
+			/* p - 1 because we don't want to pass '\n' */
+			if (!ib->ballocated && (movetomybuffer(pstart, end, p-1, ib)))
 				goto error;
-		}
-		if (p+2 < end && *p == '\n' && *(p+1) == ' '
-		    && !(*(p+2) == ' ' || *(p+2) == '\t')) {
-			/* we've to create another whitespaceless buffer */
-			if (!ib->ballocated && (movetomybuffer(buffer+1, end, p-1, ib)))
-				goto error;
-			p+=1;
+			/* p + 1 < end because 'continue' increases p so we'd skip \n
+			   we need after this for loop */
+			for (p+=1; p + 1 < end && SP(*(p + 1)); p++);
 			continue;
 		}
-		if (p+3 < end && *p == '\r' && *(p+1) == '\n' && *(p+2) == ' '
-		  	&& !(*(p+3) == ' ' || *(p+3) == '\t')) {
-			/* we've to create another whitespaceless buffer */
-			if (!ib->ballocated && (movetomybuffer(buffer+1, end, p-1, ib)))
+		if (*p=='\r' && p+2<end && *(p+1)=='\n' && SP(*(p+2))) {
+			if (!ib->ballocated && (movetomybuffer(pstart, end, p-1, ib)))
 				goto error;
-			p+=2;
+			for (p+=2; p + 1 < end && SP(*(p + 1)); p++);
 			continue;
 		}
 
+		if (isendofhash(p, end))
+			break;
+
 		/* parse error */
-		break;
-	}
-	if (p == end || *p != '"')
 		goto parseerror;
+	}
 
-	/* we step over '"' */
-	p++;
+	/* this is the final quotation mark so we step over */
+	ib->error=PARSE_OK;
+	return ;
 
-	p=eat_lws_end(p, end);
-	/*check if the header ends here*/
-	if (p>=end) {
-		LOG(L_ERR, "ERROR: parse_identity: strange EoHF\n");
+parseerror:
+	LOG( L_ERR , "ERROR: parse_identity: "
+		"unexpected char [0x%X]: <<%.*s>> .\n",
+		*p,(int)(p-buffer), ZSW(buffer));
+error:
+	return ;
+}
+
+int parse_identity_header(struct sip_msg *msg)
+{
+	struct identity_body* identity_b;
+
+
+	if ( !msg->identity
+		 && (parse_headers(msg,HDR_IDENTITY_F,0)==-1
+		 || !msg->identity) ) {
+		LOG(L_ERR,"ERROR:parse_identity_header: bad msg or missing IDENTITY header\n");
 		goto error;
 	}
-	if (*p=='\r' && p+1<end && *(p+1)=='\n') {
-		ib->error=PARSE_OK;
-		return p+2;
+
+	/* maybe the header is already parsed! */
+	if (msg->identity->parsed)
+		return 0;
+
+	identity_b=pkg_malloc(sizeof(*identity_b));
+	if (identity_b==0){
+		LOG(L_ERR, "ERROR:parse_identity_header: out of memory\n");
+		goto error;
 	}
-	if (*p=='\n') {
-		ib->error=PARSE_OK;
-		return p+1;
+	memset(identity_b, 0, sizeof(*identity_b));
+
+	parse_identity(msg->identity->body.s,
+				   msg->identity->body.s + msg->identity->body.len+1,
+				   identity_b);
+	if (identity_b->error==PARSE_ERROR){
+		free_identity(identity_b);
+		goto error;
 	}
-	LOG(L_ERR, "ERROR: Identity EoL expected\n");
-	goto error;
+	msg->identity->parsed=(void*)identity_b;
 
-parseerror:
-	LOG( L_ERR , "ERROR: parse_identity: "
-		"unexpected char [%c]: <<%.*s>> .\n",
-		*p,(int)(p-buffer), ZSW(buffer));
+	return 0;
 error:
-	return p;
+	return -1;
 }
 
-
 void free_identity(struct identity_body *ib)
 {
 	if (ib->ballocated)

+ 99 - 53
parser/parse_identityinfo.c

@@ -1,5 +1,5 @@
 /*
- * $Id$ 
+ * $Id$
  *
  * Copyright (c) 2007 iptelorg GmbH
  *
@@ -34,14 +34,15 @@
 #include "parser_f.h"  /* eat_space_end and so on */
 
 
-char* parse_identityinfo(char *buffer, char *end, struct identityinfo_body *ii_b)
+void parse_identityinfo(char *buffer, char *end, struct identityinfo_body *ii_b)
 {
 	int status = II_START;
 	int mainstatus = II_M_START;
 	char *p;
 
 
-	if (!buffer || !end || !ii_b) return NULL;
+	if (!buffer || !end || !ii_b) return ;
+
 
 	ii_b->error = PARSE_ERROR;
 
@@ -56,35 +57,38 @@ char* parse_identityinfo(char *buffer, char *end, struct identityinfo_body *ii_b
 					goto parseerror;
 					break;
 			case 'h':
-				case 'H': /* "http://" or "https://" part  */
-					switch (status) {
-						case II_URI_BEGIN:
-							if (end - p <= 8 || strncasecmp(p,"http",strlen("http")))
-								goto parseerror;
-							p+=4;
-							if (*p == 's' || *p == 'S') p++;
-							if (memcmp(p,"://",strlen("://")))
-								goto parseerror;
-							p+=2;
-							status = II_URI_DOMAIN;
-							break;
-						case II_URI_DOMAIN:
-							status = II_URI_IPV4;
-						case II_URI_IPV4:
-						case II_URI_IPV6:
-						case II_URI_PATH:
-						case II_TOKEN:
-						case II_TAG:
-							break;
-						case II_EQUAL:
-							status = II_TOKEN;
-							mainstatus = II_M_TOKEN;
-							ii_b->alg.s = p;
-							break;
-						default:
+			case 'H': /* "http://" or "https://" part  */
+				switch (status) {
+					case II_URI_BEGIN:
+						if (end - p <= 8 || strncasecmp(p,"http",strlen("http")))
 							goto parseerror;
-					}
-					break;
+						p+=4;
+						if (*p == 's' || *p == 'S') p++;
+						if (memcmp(p,"://",strlen("://")))
+							goto parseerror;
+						p+=2;
+						status = II_URI_DOMAIN;
+						break;
+					case II_URI_DOMAIN:
+						status = II_URI_IPV4;
+					case II_URI_IPV4:
+					case II_URI_IPV6:
+					case II_URI_PATH:
+					case II_TOKEN:
+					case II_TAG:
+						break;
+					case II_EQUAL:
+						status = II_TOKEN;
+						mainstatus = II_M_TOKEN;
+						ii_b->alg.s = p;
+						break;
+					case II_LWSCRLF:
+						ii_b->error=PARSE_OK;
+						return ;
+					default:
+						goto parseerror;
+				}
+				break;
 			case '/':
 				switch(status){
 					case II_URI_IPV4:
@@ -105,7 +109,7 @@ char* parse_identityinfo(char *buffer, char *end, struct identityinfo_body *ii_b
 					mainstatus = II_M_URI_END;
 				} else
 					goto parseerror;
-					break;
+				break;
 			case ' ':
 			case '\t':
 				switch (status) {
@@ -116,6 +120,7 @@ char* parse_identityinfo(char *buffer, char *end, struct identityinfo_body *ii_b
 						status = II_LWS;
 						break;
 					case II_LWS:
+					case II_LWSCRLFSP:
 						break;
 					case II_LWSCRLF:
 						status = II_LWSCRLFSP;
@@ -137,12 +142,18 @@ char* parse_identityinfo(char *buffer, char *end, struct identityinfo_body *ii_b
 					case II_LWS:
 						status = II_LWSCR;
 						break;
+					case II_LWSCRLF:
+						ii_b->error=PARSE_OK;
+						return ;
 					default:
 						goto parseerror;
 				}
 				break;
 			case '\n':
 				switch (status) {
+					case II_LWSCRLF:
+						ii_b->error=PARSE_OK;
+						return ;
 					case II_EQUAL:
 					case II_TAG:
 					case II_SEMIC:
@@ -151,26 +162,17 @@ char* parse_identityinfo(char *buffer, char *end, struct identityinfo_body *ii_b
 					case II_LWSCR:
 						status = II_LWSCRLF;
 						break;
-						case II_TOKEN: /* if there was not '\r' */
-							ii_b->alg.len = p - ii_b->alg.s;
+					case II_TOKEN: /* if there was not '\r' */
+						ii_b->alg.len = p - ii_b->alg.s;
 					case II_ENDHEADER:
 						p=eat_lws_end(p, end);
 						/*check if the header ends here*/
 						if (p>=end) {
-							LOG(L_ERR, "ERROR: parse_date: strange EoHF\n");
+							LOG(L_ERR, "ERROR: parse_identityinfo: strange EoHF\n");
 							goto parseerror;
 						}
-						if (*p=='\r' && p+1<end && *(p+1)=='\n') {
-							ii_b->error=PARSE_OK;
-							return p+2;
-						}
-						if (*p=='\n') {
-							ii_b->error=PARSE_OK;
-							return p+1;
-						}
-						LOG(L_ERR, "ERROR: Date EoL expected\n");
-						goto error;
-						break;
+						ii_b->error=PARSE_OK;
+						return ;
 					default:
 						goto parseerror;
 				}
@@ -190,7 +192,7 @@ char* parse_identityinfo(char *buffer, char *end, struct identityinfo_body *ii_b
 						goto parseerror;
 				}
 				break;
-				case 'a': /* tag part of 'alg' parameter */
+			case 'a': /* tag part of 'alg' parameter */
 			case 'A':
 				switch (status) {
 					case II_LWS:
@@ -217,6 +219,9 @@ char* parse_identityinfo(char *buffer, char *end, struct identityinfo_body *ii_b
 						mainstatus = II_M_TOKEN;
 						ii_b->alg.s = p;
 						break;
+					case II_LWSCRLF:
+						ii_b->error=PARSE_OK;
+						return ;
 					default:
 						goto parseerror;
 				}
@@ -279,6 +284,9 @@ char* parse_identityinfo(char *buffer, char *end, struct identityinfo_body *ii_b
 						break;
 					case II_TOKEN:
 						break;
+					case II_LWSCRLF:
+						ii_b->error=PARSE_OK;
+						return ;
 					case II_URI_DOMAIN:
 						ii_b->domain.s = p;
 						status = II_URI_IPV4;
@@ -288,22 +296,60 @@ char* parse_identityinfo(char *buffer, char *end, struct identityinfo_body *ii_b
 						    || *p == '-'
 						    || *p == '.'
 						    || *p == ':' )
-							break;
+						break;
 					case II_START:
 						goto parseerror;
 				}
 				break;
 		}
 	}
+	/* we successfully parse the header */
+	ii_b->error=PARSE_OK;
+	return ;
 
 parseerror:
-		LOG( L_ERR , "ERROR: parse_identityinfo: "
-		"unexpected char [%c] in status %d: <<%.*s>> .\n",
-		*p,status, (int)(p-buffer), ZSW(buffer));
-error:
-		return p;
+	LOG( L_ERR , "ERROR: parse_identityinfo: "
+	"unexpected char [%c] in status %d: <<%.*s>> .\n",
+	*p,status, (int)(p-buffer), ZSW(p));
+	return ;
 }
 
+int parse_identityinfo_header(struct sip_msg *msg)
+{
+	struct identityinfo_body* identityinfo_b;
+
+
+	if ( !msg->identity_info
+		 && (parse_headers(msg,HDR_IDENTITY_INFO_F,0)==-1
+			 || !msg->identity_info) ) {
+		LOG(L_ERR,"ERROR:parse_identityinfo_header: bad msg or missing IDENTITY-INFO header\n");
+		goto error;
+	}
+
+	/* maybe the header is already parsed! */
+	if (msg->identity_info->parsed)
+		return 0;
+
+	identityinfo_b=pkg_malloc(sizeof(*identityinfo_b));
+	if (identityinfo_b==0){
+		LOG(L_ERR, "ERROR:parse_identityinfo_header: out of memory\n");
+		goto error;
+	}
+	memset(identityinfo_b, 0, sizeof(*identityinfo_b));
+
+	parse_identityinfo(msg->identity_info->body.s,
+					   msg->identity_info->body.s + msg->identity_info->body.len+1,
+					   identityinfo_b);
+	if (identityinfo_b->error==PARSE_ERROR){
+		free_identityinfo(identityinfo_b);
+		goto error;
+	}
+	msg->identity_info->parsed=(void*)identityinfo_b;
+
+	return 0;
+error:
+	return -1;
+}
 
 void free_identityinfo(struct identityinfo_body *ii_b)
 {