static inline str* extract_mangled_fromuri(str *mangled_from_hdr) { struct to_body from_b; struct hdr_field hdr; char *tmp,*end; if (mangled_from_hdr->len == 0 || mangled_from_hdr->s == NULL) return NULL; end = mangled_from_hdr->s+mangled_from_hdr->len; tmp=parse_hname2(mangled_from_hdr->s,end,&hdr); if (hdr.type==HDR_ERROR_T) { LM_ERR("bad from header\n"); return NULL; } tmp=eat_lws_end(tmp, end); if (tmp >= end) { LM_ERR("empty header\n"); return NULL; } parse_to(tmp,end,&from_b); if (from_b.error == PARSE_ERROR) { LM_ERR("bad from header [%.*s]\n",mangled_from_hdr->len,mangled_from_hdr->s); return NULL; } extracted_from_uri = from_b.uri; free_to_params(&from_b); LM_DBG("extracted from uri [%.*s]\n",extracted_from_uri.len,extracted_from_uri.s); return &extracted_from_uri; }
/*BUGGY*/ char* parse_cseq(char* const buf, const char* const end, struct cseq_body* const cb) { char *t, *m, *m_end; cb->error=PARSE_ERROR; t=buf; cb->number.s=t; t=eat_token_end(t, end); if (t>=end) goto error; cb->number.len=t-cb->number.s; m=eat_space_end(t, end); m_end=eat_token_end(m, end); if (m_end>=end) { LOG(L_ERR, "ERROR: parse_cseq: " "method terminated unexpectedly\n"); goto error; } if (m_end==m){ /* null method*/ LOG(L_ERR, "ERROR:parse_cseq: no method found\n"); goto error; } cb->method.s=m; t=m_end; cb->method.len=t-cb->method.s; /* Cache method id */ if (parse_method_name(&cb->method, &cb->method_id)!=0){ LOG(L_ERR, "Cannot parse method string\n"); goto error; } /* there may be trailing LWS * (it was not my idea to put it in SIP; -jiri ) */ t=eat_lws_end(t, end); /*check if the header ends here*/ if (t>=end) { LOG(L_ERR, "ERROR: parse_cseq: strange EoHF\n"); goto error; } if (*t=='\r' && t+1<end && *(t+1)=='\n') { cb->error=PARSE_OK; return t+2; } if (*t=='\n') { cb->error=PARSE_OK; return t+1; } LOG(L_ERR, "ERROR: CSeq EoL expected\n"); error: LOG(L_ERR, "ERROR: parse_cseq: bad cseq\n"); return t; }
char* parse_cseq(char *buf, char* end, struct cseq_body* cb) { char *t, *m, *m_end; cb->error=PARSE_ERROR; t=buf; cb->number.s=t; t=eat_token_end(t, end); if (t>=end) goto error; cb->number.len=t-cb->number.s; m=eat_space_end(t, end); m_end=eat_token_end(m, end); if (m_end>=end) { LM_ERR("method terminated unexpectedly\n"); goto error; } if (m_end==m){ /* null method*/ LM_ERR("no method found\n"); goto error; } cb->method.s=m; t=m_end; cb->method.len=t-cb->method.s; /* cache the method id */ if(parse_method(cb->method.s, t, (unsigned int*)&cb->method_id)==0) { LM_ERR("cannot parse the method\n"); goto error; } /* there may be trailing LWS * (it was not my idea to put it in SIP; -jiri ) */ t=eat_lws_end(t, end); /*check if the header ends here*/ if (t>=end) { LM_ERR("strange EoHF\n"); goto error; } if (*t=='\r' && t+1<end && *(t+1)=='\n') { cb->error=PARSE_OK; return t+2; } if (*t=='\n') { cb->error=PARSE_OK; return t+1; } LM_ERR("expecting CSeq EoL\n"); error: LM_ERR("bad cseq\n"); return t; }
/*! \brief Parse the Retry-after header field */ char* parse_retry_after(char* const buf, const char* const end, unsigned* const after, int* const err) { char *t; int i; unsigned val; val=0; t=buf; t=eat_lws_end(t, end); if (t>=end) goto error; for (i=0; t<end; i++,t++){ if ((*t >= '0') && (*t <= '9')){ val=val*10+(*t-'0'); }else{ switch(*t){ /* for now we don't care about retry-after params or comment*/ case ' ': case '\t': case ';': case '\r': case '\n': case '(': goto found; default: /* invalid char */ goto error; } } } goto error_nocrlf; /* end reached without encountering cr or lf */ found: if (i>10 || i==0) /* too many or too few digits */ goto error; *after=val; /* find the end of header */ for (; t<end; t++){ if (*t=='\n'){ if (((t+1)<end) && (*(t+1)=='\r')) t++; if (((t+1)<end) && (*(t+1)==' ' || *(t+1)=='\t')){ t++; continue; /* line folding ... */ } *err=0; return t+1; } } error_nocrlf: LOG(L_ERR, "ERROR: parse_retry_after: strange EoHF\n"); goto error; error: LOG(L_ERR, "ERROR: parse_retry_after: bad Retry-After header \n"); *err=1; return t; }
/* returns pointer to next header line, and fill hdr_f ; * if at end of header returns pointer to the last crlf (always buf)*/ char* get_sdp_hdr_field(char* buf, char* end, struct hdr_field* hdr) { char* tmp; char *match; if ((*buf)=='\n' || (*buf)=='\r'){ /* double crlf or lflf or crcr */ hdr->type=HDR_EOH_T; return buf; } tmp=parse_hname2(buf, end, hdr); if (hdr->type==HDR_ERROR_T){ LM_ERR("bad header\n"); goto error; } /* eliminate leading whitespace */ tmp=eat_lws_end(tmp, end); if (tmp>=end) { LM_ERR("hf empty\n"); goto error; } /* just skip over it */ hdr->body.s=tmp; /* find end of header */ /* find lf */ do{ match=memchr(tmp, '\n', end-tmp); if (match){ match++; }else { LM_ERR("bad body for <%s>(%d)\n", hdr->name.s, hdr->type); tmp=end; goto error; } tmp=match; }while( match<end &&( (*match==' ')||(*match=='\t') ) ); tmp=match; hdr->body.len=match-hdr->body.s; /* jku: if \r covered by current length, shrink it */ trim_r( hdr->body ); hdr->len=tmp-hdr->name.s; return tmp; error: LM_DBG("error exit\n"); hdr->type=HDR_ERROR_T; hdr->len=tmp-hdr->name.s; return tmp; }
/* returns pointer to next header line, and fill hdr_f ; * if at end of header returns pointer to the last crlf (always buf)*/ char* get_hdr_field(char* const buf, char* const end, struct hdr_field* const hdr) { char *tmp = 0; char *match; struct via_body *vb; struct cseq_body* cseq_b; struct to_body* to_b; int integer, err; unsigned uval; if(!buf) { DBG("null buffer pointer\n"); goto error; } if ((*buf)=='\n' || (*buf)=='\r') { /* double crlf or lflf or crcr */ DBG("found end of header\n"); hdr->type=HDR_EOH_T; return buf; } tmp=parse_hname(buf, end, hdr); if (hdr->type==HDR_ERROR_T) { LOG(L_ERR, "ERROR: get_hdr_field: bad header\n"); goto error; } /* eliminate leading whitespace */ tmp=eat_lws_end(tmp, end); if (tmp>=end) { LOG(L_ERR, "ERROR: get_hdr_field: HF empty\n"); goto error; } /* if header-field well-known, parse it, find its end otherwise ; * after leaving the hdr->type switch, tmp should be set to the * next header field */ switch(hdr->type) { case HDR_VIA_T: /* keep number of vias parsed -- we want to report it in replies for diagnostic purposes */ via_cnt++; vb=pkg_malloc(sizeof(struct via_body)); if (vb==0) { LOG(L_ERR, "get_hdr_field: out of memory\n"); goto error; } memset(vb,0,sizeof(struct via_body)); hdr->body.s=tmp; tmp=parse_via(tmp, end, vb); if (vb->error==PARSE_ERROR) { LOG(L_ERR, "ERROR: get_hdr_field: bad via\n"); free_via_list(vb); goto error; } hdr->parsed=vb; vb->hdr.s=hdr->name.s; vb->hdr.len=hdr->name.len; hdr->body.len=tmp-hdr->body.s; break; case HDR_CSEQ_T: cseq_b=pkg_malloc(sizeof(struct cseq_body)); if (cseq_b==0) { LOG(L_ERR, "get_hdr_field: out of memory\n"); goto error; } memset(cseq_b, 0, sizeof(struct cseq_body)); hdr->body.s=tmp; tmp=parse_cseq(tmp, end, cseq_b); if (cseq_b->error==PARSE_ERROR) { LOG(L_ERR, "ERROR: get_hdr_field: bad cseq\n"); free_cseq(cseq_b); goto error; } hdr->parsed=cseq_b; hdr->body.len=tmp-hdr->body.s; DBG("get_hdr_field: cseq <%.*s>: <%.*s> <%.*s>\n", hdr->name.len, ZSW(hdr->name.s), cseq_b->number.len, ZSW(cseq_b->number.s), cseq_b->method.len, cseq_b->method.s); break; case HDR_TO_T: to_b=pkg_malloc(sizeof(struct to_body)); if (to_b==0) { LOG(L_ERR, "get_hdr_field: out of memory\n"); goto error; } memset(to_b, 0, sizeof(struct to_body)); hdr->body.s=tmp; tmp=parse_to(tmp, end,to_b); if (to_b->error==PARSE_ERROR) { LOG(L_ERR, "ERROR: get_hdr_field: bad to header\n"); free_to(to_b); goto error; } hdr->parsed=to_b; hdr->body.len=tmp-hdr->body.s; DBG("DEBUG: get_hdr_field: <%.*s> [%d]; uri=[%.*s] \n", hdr->name.len, ZSW(hdr->name.s), hdr->body.len, to_b->uri.len,ZSW(to_b->uri.s)); DBG("DEBUG: to body [%.*s]\n",to_b->body.len, ZSW(to_b->body.s)); break; case HDR_CONTENTLENGTH_T: hdr->body.s=tmp; tmp=parse_content_length(tmp,end, &integer); if (tmp==0) { LOG(L_ERR, "ERROR:get_hdr_field: bad content_length header\n"); goto error; } hdr->parsed=(void*)(long)integer; hdr->body.len=tmp-hdr->body.s; DBG("DEBUG: get_hdr_body : content_length=%d\n", (int)(long)hdr->parsed); break; case HDR_RETRY_AFTER_T: hdr->body.s=tmp; tmp=parse_retry_after(tmp,end, &uval, &err); if (err) { LOG(L_ERR, "ERROR:get_hdr_field: bad retry_after header\n"); goto error; } hdr->parsed=(void*)(unsigned long)uval; hdr->body.len=tmp-hdr->body.s; DBG("DEBUG: get_hdr_body : retry_after=%d\n", (unsigned)(long)hdr->parsed); break; case HDR_IDENTITY_T: case HDR_DATE_T: case HDR_IDENTITY_INFO_T: case HDR_SUPPORTED_T: case HDR_REQUIRE_T: case HDR_CONTENTTYPE_T: case HDR_FROM_T: case HDR_CALLID_T: case HDR_CONTACT_T: case HDR_ROUTE_T: case HDR_RECORDROUTE_T: case HDR_MAXFORWARDS_T: case HDR_AUTHORIZATION_T: case HDR_EXPIRES_T: case HDR_PROXYAUTH_T: case HDR_PROXYREQUIRE_T: case HDR_UNSUPPORTED_T: case HDR_ALLOW_T: case HDR_EVENT_T: case HDR_ACCEPT_T: case HDR_ACCEPTLANGUAGE_T: case HDR_ORGANIZATION_T: case HDR_PRIORITY_T: case HDR_SUBJECT_T: case HDR_USERAGENT_T: case HDR_SERVER_T: case HDR_CONTENTDISPOSITION_T: case HDR_DIVERSION_T: case HDR_RPID_T: case HDR_SIPIFMATCH_T: case HDR_REFER_TO_T: case HDR_SESSIONEXPIRES_T: case HDR_MIN_SE_T: case HDR_SUBSCRIPTION_STATE_T: case HDR_ACCEPTCONTACT_T: case HDR_ALLOWEVENTS_T: case HDR_CONTENTENCODING_T: case HDR_REFERREDBY_T: case HDR_REJECTCONTACT_T: case HDR_REQUESTDISPOSITION_T: case HDR_WWW_AUTHENTICATE_T: case HDR_PROXY_AUTHENTICATE_T: case HDR_PATH_T: case HDR_PRIVACY_T: case HDR_PAI_T: case HDR_PPI_T: case HDR_REASON_T: case HDR_OTHER_T: /* just skip over it */ hdr->body.s=tmp; /* find end of header */ /* find lf */ do { match=q_memchr(tmp, '\n', end-tmp); if (match) { match++; } else { LOG(L_ERR, "ERROR: get_hdr_field: bad body for <%s>(%d)\n", hdr->name.s, hdr->type); /* abort(); */ tmp=end; goto error; } tmp=match; } while( match<end &&( (*match==' ')||(*match=='\t') ) ); tmp=match; hdr->body.len=match-hdr->body.s; break; default: LOG(L_CRIT, "BUG: get_hdr_field: unknown header type %d\n", hdr->type); goto error; } /* jku: if \r covered by current length, shrink it */ trim_r( hdr->body ); hdr->len=tmp-hdr->name.s; return tmp; error: DBG("get_hdr_field: error exit\n"); STATS_BAD_MSG_HDR(); hdr->type=HDR_ERROR_T; hdr->len=tmp-hdr->name.s; return tmp; }
/* returns pointer to next header line, and fill hdr_f ; * if at end of header returns pointer to the last crlf (always buf)*/ char* get_sdp_hdr_field(char* buf, char* end, struct hdr_field* hdr) { char* tmp; char *match; if ((*buf)=='\n' || (*buf)=='\r'){ /* double crlf or lflf or crcr */ hdr->type=HDR_EOH_T; return buf; } tmp=parse_hname2(buf, end, hdr); if (hdr->type==HDR_ERROR_T){ LM_ERR("bad header\n"); goto error; } /* eliminate leading whitespace */ tmp=eat_lws_end(tmp, end); if (tmp>=end) { LM_ERR("hf empty\n"); goto error; } /* if header-field well-known, parse it, find its end otherwise ; * after leaving the hdr->type switch, tmp should be set to the * next header field */ switch(hdr->type){ case HDR_CONTENTTYPE_T: case HDR_CONTENTDISPOSITION_T: /* just skip over it */ hdr->body.s=tmp; /* find end of header */ /* find lf */ do{ match=q_memchr(tmp, '\n', end-tmp); if (match){ match++; }else { LM_ERR("bad body for <%s>(%d)\n", hdr->name.s, hdr->type); tmp=end; goto error; } tmp=match; }while( match<end &&( (*match==' ')||(*match=='\t') ) ); tmp=match; hdr->body.len=match-hdr->body.s; break; default: LM_CRIT("unknown header type %d\n", hdr->type); goto error; } /* jku: if \r covered by current length, shrink it */ trim_r( hdr->body ); hdr->len=tmp-hdr->name.s; return tmp; error: LM_DBG("error exit\n"); hdr->type=HDR_ERROR_T; hdr->len=tmp-hdr->name.s; return tmp; }
/* returns pointer to next header line, and fill hdr_f ; * if at end of header returns pointer to the last crlf (always buf)*/ char* get_hdr_field(char* buf, char* end, struct hdr_field* hdr) { char* tmp; char *match; struct via_body *vb; struct cseq_body* cseq_b; struct to_body* to_b; int integer; if ((*buf)=='\n' || (*buf)=='\r'){ /* double crlf or lflf or crcr */ LM_DBG("found end of header\n"); hdr->type=HDR_EOH_T; return buf; } tmp=parse_hname(buf, end, hdr); if (hdr->type==HDR_ERROR_T){ LM_ERR("bad header\n"); goto error_bad_hdr; } /* eliminate leading whitespace */ tmp=eat_lws_end(tmp, end); if (tmp>=end) { LM_ERR("hf empty\n"); goto error_bad_hdr; } /* if header-field well-known, parse it, find its end otherwise ; * after leaving the hdr->type switch, tmp should be set to the * next header field */ switch(hdr->type){ case HDR_VIA_T: /* keep number of vias parsed -- we want to report it in replies for diagnostic purposes */ via_cnt++; vb=pkg_malloc(sizeof(struct via_body)); if (vb==0){ LM_ERR("out of pkg memory\n"); goto error; } memset(vb,0,sizeof(struct via_body)); hdr->body.s=tmp; tmp=parse_via(tmp, end, vb); if (vb->error==PARSE_ERROR){ LM_ERR("bad via\n"); free_via_list(vb); set_err_info(OSER_EC_PARSER, OSER_EL_MEDIUM, "error parsing Via"); set_err_reply(400, "bad Via header"); goto error; } hdr->parsed=vb; vb->hdr.s=hdr->name.s; vb->hdr.len=hdr->name.len; hdr->body.len=tmp-hdr->body.s; break; case HDR_CSEQ_T: cseq_b=pkg_malloc(sizeof(struct cseq_body)); if (cseq_b==0){ LM_ERR("out of pkg memory\n"); goto error; } memset(cseq_b, 0, sizeof(struct cseq_body)); hdr->body.s=tmp; tmp=parse_cseq(tmp, end, cseq_b); if (cseq_b->error==PARSE_ERROR){ LM_ERR("bad cseq\n"); pkg_free(cseq_b); set_err_info(OSER_EC_PARSER, OSER_EL_MEDIUM, "error parsing CSeq`"); set_err_reply(400, "bad CSeq header"); goto error; } hdr->parsed=cseq_b; hdr->body.len=tmp-hdr->body.s; LM_DBG("cseq <%.*s>: <%.*s> <%.*s>\n", hdr->name.len, ZSW(hdr->name.s), cseq_b->number.len, ZSW(cseq_b->number.s), cseq_b->method.len, cseq_b->method.s); break; case HDR_TO_T: to_b=pkg_malloc(sizeof(struct to_body)); if (to_b==0){ LM_ERR("out of pkg memory\n"); goto error; } memset(to_b, 0, sizeof(struct to_body)); hdr->body.s=tmp; tmp=parse_to(tmp, end,to_b); if (to_b->error==PARSE_ERROR){ LM_ERR("bad to header\n"); pkg_free(to_b); set_err_info(OSER_EC_PARSER, OSER_EL_MEDIUM, "error parsing To header"); set_err_reply(400, "bad header"); goto error; } hdr->parsed=to_b; hdr->body.len=tmp-hdr->body.s; LM_DBG("<%.*s> [%d]; uri=[%.*s] \n", hdr->name.len, ZSW(hdr->name.s), hdr->body.len, to_b->uri.len,ZSW(to_b->uri.s)); LM_DBG("to body [%.*s]\n",to_b->body.len, ZSW(to_b->body.s)); break; case HDR_CONTENTLENGTH_T: hdr->body.s=tmp; tmp=parse_content_length(tmp,end, &integer); if (tmp==0){ LM_ERR("bad content_length header\n"); set_err_info(OSER_EC_PARSER, OSER_EL_MEDIUM, "error parsing Content-Length"); set_err_reply(400, "bad Content-Length header"); goto error; } hdr->parsed=(void*)(long)integer; hdr->body.len=tmp-hdr->body.s; LM_DBG("content_length=%d\n", (int)(long)hdr->parsed); break; case HDR_SUPPORTED_T: case HDR_CONTENTTYPE_T: case HDR_FROM_T: case HDR_CALLID_T: case HDR_CONTACT_T: case HDR_ROUTE_T: case HDR_RECORDROUTE_T: case HDR_PATH_T: case HDR_MAXFORWARDS_T: case HDR_AUTHORIZATION_T: case HDR_EXPIRES_T: case HDR_PROXYAUTH_T: case HDR_PROXYREQUIRE_T: case HDR_UNSUPPORTED_T: case HDR_ALLOW_T: case HDR_EVENT_T: case HDR_ACCEPT_T: case HDR_ACCEPTLANGUAGE_T: case HDR_ORGANIZATION_T: case HDR_PRIORITY_T: case HDR_SUBJECT_T: case HDR_USERAGENT_T: case HDR_CONTENTDISPOSITION_T: case HDR_ACCEPTDISPOSITION_T: case HDR_DIVERSION_T: case HDR_RPID_T: case HDR_REFER_TO_T: case HDR_SESSION_EXPIRES_T: case HDR_MIN_SE_T: case HDR_MIN_EXPIRES_T: case HDR_PPI_T: case HDR_PAI_T: case HDR_PRIVACY_T: case HDR_RETRY_AFTER_T: case HDR_CALL_INFO_T: case HDR_WWW_AUTHENTICATE_T: case HDR_PROXY_AUTHENTICATE_T: case HDR_OTHER_T: /* just skip over it */ hdr->body.s=tmp; /* find end of header */ /* find lf */ do{ match=q_memchr(tmp, '\n', end-tmp); if (match){ match++; }else { LM_ERR("bad body for <%s>(%d)\n", hdr->name.s, hdr->type); tmp=end; goto error_bad_hdr; } tmp=match; }while( match<end &&( (*match==' ')||(*match=='\t') ) ); tmp=match; hdr->body.len=match-hdr->body.s; break; default: LM_CRIT("unknown header type %d\n", hdr->type); goto error; } /* jku: if \r covered by current length, shrink it */ trim_r( hdr->body ); hdr->len=tmp-hdr->name.s; return tmp; error_bad_hdr: set_err_info(OSER_EC_PARSER, OSER_EL_MEDIUM, "error parsing headers"); set_err_reply(400, "bad headers"); error: LM_DBG("error exit\n"); update_stat( bad_msg_hdr, 1); hdr->type=HDR_ERROR_T; hdr->len=tmp-hdr->name.s; return tmp; }
/*! \brief Parse Identity-info header field */ 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 ; ii_b->error = PARSE_ERROR; for(p = buffer; p < end; p++) { switch(*p) { case '<': if (status == II_START) { status=II_URI_BEGIN; mainstatus = II_M_URI_BEGIN; ii_b->uri.s = p + 1; } else { goto parseerror; } break; case 'h': case 'H': /* "http://" or "https://" part */ switch (status) { case II_URI_BEGIN: if (end - p <= 8 || strncasecmp(p, "http", 4)) 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; case II_LWSCRLF: ii_b->error=PARSE_OK; return ; default: goto parseerror; } break; case '/': switch(status){ case II_URI_IPV4: ii_b->domain.len = p - ii_b->domain.s; status = II_URI_PATH; break; case II_URI_PATH: break; case II_URI_IPV6: default: goto parseerror; } break; case '>': if (status == II_URI_PATH) { ii_b->uri.len = p - ii_b->uri.s; status = II_URI_END; mainstatus = II_M_URI_END; } else goto parseerror; break; case ' ': case '\t': switch (status) { case II_EQUAL: case II_TAG: case II_SEMIC: case II_URI_END: status = II_LWS; break; case II_LWS: case II_LWSCRLFSP: break; case II_LWSCRLF: status = II_LWSCRLFSP; break; default: goto parseerror; } break; case '\r': switch (status) { case II_TOKEN: ii_b->alg.len = p - ii_b->alg.s; status = II_ENDHEADER; break; case II_EQUAL: case II_TAG: case II_SEMIC: case II_URI_END: 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: case II_URI_END: case II_LWS: 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_ENDHEADER: p=eat_lws_end(p, end); /*check if the header ends here*/ if (p>=end) { LM_ERR("strange EoHF\n"); goto parseerror; } ii_b->error=PARSE_OK; return ; default: goto parseerror; } break; case ';': switch (status) { case II_URI_END: case II_LWS: case II_LWSCRLFSP: if (mainstatus == II_M_URI_END) { status = II_SEMIC; mainstatus = II_M_SEMIC; } else goto parseerror; break; default: goto parseerror; } break; case 'a': /* tag part of 'alg' parameter */ case 'A': switch (status) { case II_LWS: case II_LWSCRLFSP: case II_SEMIC: if (mainstatus == II_M_SEMIC) { mainstatus = II_M_TAG; status = II_TAG; if (end - p <= 3 || strncasecmp(p,"alg",strlen("alg"))) goto parseerror; p+=2; } else goto parseerror; break; case II_URI_DOMAIN: status = II_URI_IPV4; case II_URI_IPV4: case II_URI_IPV6: case II_URI_PATH: case II_TOKEN: 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_TAG: case II_LWS: case II_LWSCRLFSP: if (mainstatus == II_M_TAG) { status = II_EQUAL; mainstatus = II_M_EQUAL; } else goto parseerror; break; case II_URI_PATH: break; default: goto parseerror; } break; case '[': switch (status) { case II_URI_DOMAIN: status = II_URI_IPV6; ii_b->domain.s = p + 1; break; default: goto parseerror; } break; case ']': switch (status) { case II_URI_IPV6: ii_b->domain.len = p - ii_b->domain.s; status = II_URI_PATH; break; case II_URI_IPV4: case II_URI_PATH: goto parseerror; } break; case ':': if (status == II_URI_IPV4) { ii_b->domain.len = p - ii_b->domain.s; status = II_URI_PATH; } break; default: switch (status) { case II_EQUAL: case II_LWS: case II_LWSCRLFSP: if (mainstatus == II_M_EQUAL) { status = II_TOKEN; mainstatus = II_M_TOKEN; ii_b->alg.s = p; } else goto parseerror; 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; case II_URI_IPV4: case II_URI_IPV6: if (isalnum(*p) || *p == '-' || *p == '.' || *p == ':' ) break; case II_START: goto parseerror; } break; } } /* we successfully parse the header */ ii_b->error=PARSE_OK; return ; parseerror: LM_ERR("unexpected char [%c] in status %d: <<%.*s>> .\n", *p,status, (int)(p-buffer), ZSW(p)); return ; }
/* returns pointer to next header line, and fill hdr_f ; * if at end of header returns pointer to the last crlf (always buf)*/ char* get_hdr_field(char* buf, char* end, struct hdr_field* hdr) { char* tmp; char *match; struct via_body *vb; struct cseq_body* cseq_b; struct to_body* to_b; int integer; if ((*buf)=='\n' || (*buf)=='\r'){ /* double crlf or lflf or crcr */ DBG("found end of header\n"); hdr->type=HDR_EOH; return buf; } tmp=parse_hname(buf, end, hdr); if (hdr->type==HDR_ERROR){ LOG(L_ERR, "ERROR: get_hdr_field: bad header\n"); goto error; } /* eliminate leading whitespace */ tmp=eat_lws_end(tmp, end); if (tmp>=end) { LOG(L_ERR, "ERROR: get_hdr_field: HF empty\n"); goto error; } /* if header-field well-known, parse it, find its end otherwise ; * after leaving the hdr->type switch, tmp should be set to the * next header field */ switch(hdr->type){ case HDR_VIA: /* keep number of vias parsed -- we want to report it in replies for diagnostic purposes */ via_cnt++; vb=pkg_malloc(sizeof(struct via_body)); if (vb==0){ LOG(L_ERR, "get_hdr_field: out of memory\n"); goto error; } memset(vb,0,sizeof(struct via_body)); hdr->body.s=tmp; tmp=parse_via(tmp, end, vb); if (vb->error==PARSE_ERROR){ LOG(L_ERR, "ERROR: get_hdr_field: bad via\n"); free_via_list(vb); goto error; } hdr->parsed=vb; vb->hdr.s=hdr->name.s; vb->hdr.len=hdr->name.len; hdr->body.len=tmp-hdr->body.s; break; case HDR_CSEQ: cseq_b=pkg_malloc(sizeof(struct cseq_body)); if (cseq_b==0){ LOG(L_ERR, "get_hdr_field: out of memory\n"); goto error; } memset(cseq_b, 0, sizeof(struct cseq_body)); hdr->body.s=tmp; tmp=parse_cseq(tmp, end, cseq_b); if (cseq_b->error==PARSE_ERROR){ LOG(L_ERR, "ERROR: get_hdr_field: bad cseq\n"); pkg_free(cseq_b); goto error; } hdr->parsed=cseq_b; hdr->body.len=tmp-hdr->body.s; DBG("get_hdr_field: cseq <%.*s>: <%.*s> <%.*s>\n", hdr->name.len, ZSW(hdr->name.s), cseq_b->number.len, ZSW(cseq_b->number.s), cseq_b->method.len, cseq_b->method.s); break; case HDR_TO: to_b=pkg_malloc(sizeof(struct to_body)); if (to_b==0){ LOG(L_ERR, "get_hdr_field: out of memory\n"); goto error; } memset(to_b, 0, sizeof(struct to_body)); hdr->body.s=tmp; tmp=parse_to(tmp, end,to_b); if (to_b->error==PARSE_ERROR){ LOG(L_ERR, "ERROR: get_hdr_field: bad to header\n"); pkg_free(to_b); goto error; } hdr->parsed=to_b; hdr->body.len=tmp-hdr->body.s; DBG("DEBUG: get_hdr_field: <%.*s> [%d]; uri=[%.*s] \n", hdr->name.len, ZSW(hdr->name.s), hdr->body.len, to_b->uri.len,ZSW(to_b->uri.s)); DBG("DEBUG: to body [%.*s]\n",to_b->body.len, ZSW(to_b->body.s)); break; case HDR_CONTENTLENGTH: hdr->body.s=tmp; tmp=parse_content_length(tmp,end, &integer); if (tmp==0){ LOG(L_ERR, "ERROR:get_hdr_field: bad content_length header\n"); goto error; } hdr->parsed=(void*)(long)integer; hdr->body.len=tmp-hdr->body.s; DBG("DEBUG: get_hdr_body : content_length=%d\n", (int)(long)hdr->parsed); break; case HDR_SUPPORTED: case HDR_CONTENTTYPE: case HDR_FROM: case HDR_CALLID: case HDR_CONTACT: case HDR_ROUTE: case HDR_RECORDROUTE: case HDR_MAXFORWARDS: case HDR_AUTHORIZATION: case HDR_EXPIRES: case HDR_PROXYAUTH: case HDR_PROXYREQUIRE: case HDR_UNSUPPORTED: case HDR_ALLOW: case HDR_EVENT: case HDR_ACCEPT: case HDR_ACCEPTLANGUAGE: case HDR_ORGANIZATION: case HDR_PRIORITY: case HDR_SUBJECT: case HDR_USERAGENT: case HDR_CONTENTDISPOSITION: case HDR_ACCEPTDISPOSITION: case HDR_DIVERSION: case HDR_RPID: case HDR_OTHER: /* just skip over it */ hdr->body.s=tmp; /* find end of header */ /* find lf */ do{ match=q_memchr(tmp, '\n', end-tmp); if (match){ match++; }else { LOG(L_ERR, "ERROR: get_hdr_field: bad body for <%s>(%d)\n", hdr->name.s, hdr->type); /* abort(); */ tmp=end; goto error; } tmp=match; }while( match<end &&( (*match==' ')||(*match=='\t') ) ); tmp=match; hdr->body.len=match-hdr->body.s; break; default: LOG(L_CRIT, "BUG: get_hdr_field: unknown header type %d\n", hdr->type); goto error; } /* jku: if \r covered by current length, shrink it */ trim_r( hdr->body ); hdr->len=tmp-hdr->name.s; return tmp; error: DBG("get_hdr_field: error exit\n"); hdr->type=HDR_ERROR; hdr->len=tmp-hdr->name.s; return tmp; }