📄 msg_parser.c
字号:
else h = msg_header_alloc(home, hc, copy_buffer ? slen + 1 : 0); if (!h) return NULL; if (s) { if (copy_buffer) s = memcpy(MSG_HEADER_DATA(h), s, slen); s[slen] = '\0'; if (hc->hc_kind == msg_kind_list && *hh) { n = hc->hc_parse(home, *hh, s, slen); /* Clear if adding new header disturbs existing headers */ clear = *hh != h && !copy_buffer; if (clear) msg_fragment_clear((*hh)->sh_common); } else n = hc->hc_parse(home, h, s, slen); if (n < 0) { msg->m_extract_err |= hr->hr_flags; if (hc->hc_critical) mo->msg_flags |= MSG_FLG_ERROR; clear = 0; if (!add_to_list) { /* Try to free memory allocated by hc->hc_parse() */ for (h0 = h; h0; h0 = h_next) { h_next = h0->sh_next; if (hc->hc_params) { msg_param_t *params = *(msg_param_t **) ((char *)h0 + hc->hc_params); if (params) su_free(home, params); } if (h0 != h) su_free(home, h0); } memset(h, 0, hc->hc_size); h->sh_error->er_name = hc->hc_name; hr = msg->m_class->mc_error; h->sh_class = hr->hr_class; hh = (msg_header_t **)((char *)mo + hr->hr_offset); } } } if (clear) for (hh = &(*hh)->sh_next; *hh; *hh = (*hh)->sh_next) msg_chain_remove(msg, *hh); else if (h != *hh) append_parsed(msg, mo, hh, h, 0); return h;}/** Decode a message header. */msg_header_t *msg_header_d(su_home_t *home, msg_t const *msg, char const *b){ msg_mclass_t const *mc = msg->m_class; msg_href_t const *hr = mc->mc_unknown; int n; /* Length of header contents */ int name_len, xtra; msg_header_t *h; char *bb; n = strlen(b); hr = msg_find_hclass(mc, b, &name_len); if (hr == NULL) return NULL; /* Strip extra whitespace at the end and begin of header */ while (n > name_len && IS_LWS(b[n - 1])) n--; if (name_len < n && IS_LWS(b[name_len])) name_len++; xtra = (n - name_len); if (!(h = msg_header_alloc(home, hr->hr_class, xtra + 1))) return NULL; bb = memcpy(MSG_HEADER_DATA(h), b + name_len, xtra), bb[xtra] = 0; if (hr->hr_class->hc_parse(home, h, bb, xtra) < 0) { hr = mc->mc_unknown; su_free(home, h); if (!(h = msg_header_alloc(home, hr->hr_class, n + 1))) return NULL; bb = memcpy(MSG_HEADER_DATA(h), b, n), bb[n] = 0; if (hr->hr_class->hc_parse(home, h, bb, n) < 0) { su_free(home, h), h = NULL; } } return h;}/** Extract a separator line */int msg_extract_separator(msg_t *msg, msg_pub_t *mo, char b[], int bsiz, int eos){ msg_mclass_t const *mc = msg->m_class; msg_href_t const *hr = mc->mc_separator; int l = CRLF_TEST(b); /* Separator length */ msg_header_t *h, **hh; /* Even if a single CR *may* be a payload separator we cannot be sure */ if (l == 0 || (!eos && bsiz == 1 && b[0] == '\r')) return 0; /* Separator */ if (!(h = msg_header_alloc(msg_home(msg), hr->hr_class, 0))) return -1; if (hr->hr_class->hc_parse(msg_home(msg), h, b, l) < 0) return -1; h->sh_data = b, h->sh_len = l; hh = (msg_header_t **)((char *)mo + hr->hr_offset); append_parsed(msg, mo, hh, h, 0); return l;}static inline msg_header_t **msg_chain_tail(msg_t const *msg);/** Extract a message body of @a body_len bytes. */int msg_extract_payload(msg_t *msg, msg_pub_t *mo, msg_header_t **return_payload, unsigned body_len, char b[], int bsiz, int eos){ msg_mclass_t const *mc = msg->m_class; msg_href_t const *hr = mc->mc_payload; msg_header_t *h, **hh, *h0; msg_payload_t *pl; char *x; if (msg == NULL || mo == NULL) return -1; assert(!msg->m_chunk); if (return_payload == NULL) return_payload = &h0; *return_payload = NULL; assert(body_len > 0); /* Allocate header structure for payload */ if (!(h = msg_header_alloc(msg_home(msg), hr->hr_class, 0))) return -1; hh = (msg_header_t **)((char *)mo + hr->hr_offset); append_parsed(msg, mo, hh, h, 0); pl = h->sh_payload; *return_payload = h; if (bsiz >= body_len) { /* We have a complete body. */ h->sh_data = b, h->sh_len = body_len; pl->pl_data = b, pl->pl_len = body_len; return body_len; } if (msg->m_maxsize != 0 && body_len > msg->m_maxsize) { mo->msg_flags |= MSG_FLG_TOOLARGE; return -1; } assert(msg->m_buffer->mb_commit == bsiz); assert(b == msg->m_buffer->mb_data + msg->m_buffer->mb_used); if (msg->m_buffer->mb_used + body_len <= msg->m_buffer->mb_size) { /* We don't have a complete body, but we have big enough buffer for it. */ msg->m_chunk = pl; h->sh_data = b, h->sh_len = bsiz; pl->pl_data = b, pl->pl_len = body_len; if (msg->m_buffer->mb_used + body_len < msg->m_buffer->mb_size) /* NUL-terminate payload */ b[body_len++] = '\0'; /* Mark the rest of the body as used in the buffer */ /* msg_buf_commit(msg, body_len - bsiz, eos); */ msg_buf_used(msg, body_len); return bsiz; } /* We don't have big enough buffer for body. */ if (msg_get_flags(msg, MSG_FLG_CHUNKING)) { /* Application supports chunking, use multiple chunks for payload */ unsigned current, rest; current = msg->m_buffer->mb_size - msg->m_buffer->mb_used; rest = body_len - current; /* Use all the data from our current buffer */ msg_buf_used(msg, current); msg->m_chunk = pl; h->sh_data = b, h->sh_len = bsiz; pl->pl_data = b, pl->pl_len = current; for (;current < body_len; current += rest) { msg_header_t *h0 = h; /* Allocate header structure for next payload chunk */ if (!(h = msg_header_alloc(msg_home(msg), hr->hr_class, 0))) return -1; if (msg->m_chain) msg_insert_here_in_chain(msg, msg_chain_tail(msg), h); h0->sh_next = h; rest = body_len - current; if (!msg->m_streaming) { x = msg_buf_exact(msg, rest); if (x == NULL) { mo->msg_flags |= MSG_FLG_TOOLARGE; return -1; } } else { x = NULL; } if (x) { /* Mark the just-allocated buffer as used */ rest = msg->m_buffer->mb_size - msg->m_buffer->mb_used; msg_buf_used(msg, rest); } pl = h->sh_payload; h->sh_len = 0, pl->pl_len = rest; h->sh_data = x, pl->pl_data = x; } } else { /* No chunking. * * Allocate a single buffer that contains enough free space for body. * * msg_buf_exact() also copies committed but un-used data * from the old buffer (b[0] .. b[bsiz]) * to the new buffer (x[-bsiz-1]..b[-1]) */ if (!(x = msg_buf_exact(msg, body_len - bsiz + 1))) { if (mo->msg_flags & MSG_FLG_TOOLARGE) { msg_mark_as_complete(msg, MSG_FLG_TRUNC); return bsiz; } return -1; } /* Fake un-received data as already received and then use it */ /* msg_buf_commit(msg, body_len - bsiz + 1, eos); */ msg_buf_used(msg, body_len + 1); msg->m_chunk = h->sh_payload; x -= bsiz; /* Start of un-used data */ x[body_len] = '\0'; h->sh_data = x, h->sh_len = bsiz; pl->pl_data = x, pl->pl_len = body_len; assert(MSG_CHUNK_AVAIL(pl) == body_len - bsiz); } return bsiz;}/** Extract incomplete chunks. */static inlineint extract_incomplete_chunks(msg_t *msg, int eos){ msg_payload_t *chunk; for (chunk = msg->m_chunk; chunk; chunk = MSG_CHUNK_NEXT(chunk)) { if (MSG_CHUNK_AVAIL(chunk) != 0) break; /* The incomplete payload fragment is now complete */ assert(MSG_CHUNK_BUFFER(chunk) == chunk->pl_data + chunk->pl_len); msg->m_size += chunk->pl_common->h_len; } msg->m_chunk = chunk; if (chunk) { if (eos) { msg_mark_as_complete(msg, MSG_FLG_TRUNC); return 1; } } else { if (msg_get_flags(msg, MSG_FLG_FRAGS)) msg_mark_as_complete(msg, 0); } /**@retval 1 when message is complete * @retval 0 when message is incomplete * @retval -1 upon an error */ return chunk == NULL;}/* Extract trailers */static inline intextract_trailers(msg_t *msg, msg_pub_t *mo, char *b, int bsiz, int eos, int copy){ if (IS_CRLF(b[0])) { msg_mark_as_complete(msg, MSG_FLG_COMPLETE); return CRLF_TEST(b); } else return extract_header(msg, mo, b, bsiz, eos, copy);}/* ====================================================================== *//* Preparing (printing/encoding) a message structure for sending *//* Internal prototypes */static inline intmsg_header_name_e(char b[], int bsiz, msg_header_t const *h, int flags);static int msg_header_prepare(msg_mclass_t const *, int flags, msg_header_t *h, char *b, int bsiz);/**Encode all message fragments. * * @relates msg_s * * The function msg_prepare() prepares a message for sending. It encodes all * serialized fragments in the message. You have to call msg_serialize() * before calling msg_headers_prepare() in order to make sure that all the * heades and other message fragments are included in the chain. * * After encoding, the msg_common_s::h_data field will point to the encoding * result of size msg_common_s::h_len bytes in in each fragment. * * When multiple header fields are represented as a comma-separated list * within a single header line, the first fragment in the header will * contain all the text belonging to the header. The rest of the header * fields will have zero-length encoding with msg_common_s::h_data that * points to the end of the line. * * @return Total size of the encoded message in bytes, or -1 upon an error. * * @sa msg_extract(), msg_serialize() */int msg_prepare(msg_t *msg){ int total; assert(msg->m_chain); assert(msg_chain_errors(msg->m_chain) == 0); /* Get rid of data that was received but not yet used (parsed) */ msg_clear_committed(msg); total = msg_headers_prepare(msg, msg->m_chain, msg_object(msg)->msg_flags); if (total != -1) { msg->m_size = total; msg->m_prepared = 1; } return total;}/** Clear 'prepared' flag. */void msg_unprepare(msg_t *msg){ if (msg) msg->m_prepared = 0;}/** Return true if message is prepared. */int msg_is_prepared(msg_t const *msg){ return msg && msg->m_prepared;}/**Encode headers in chain. * * The function msg_headers_prepare() encodes all the headers in the header * chain. You have to call msg_serialize() before calling * msg_headers_prepare() in order to make sure that all the heades and other * message fragments are included in the chain. * * @return * The size of all the headers in chain, or -1 upon an error. */int msg_headers_prepare(msg_t *msg, msg_header_t *headers, int flags){ msg_mclass_t const *mc = msg->m_class; msg_header_t *h; int n = 0, bsiz = 0, used = 0; char *b; unsigned total = 0; b = msg_buf_alloc(msg, msg_min_size); bsiz = msg_buf_size(msg); if (!b) return -1; for (h = headers; h;) { if (h->sh_data) { total += h->sh_len; h = h->sh_succ; continue; } n = msg_header_prepare(mc, flags, h, b, bsiz - used); if (n < 0) { errno = EINVAL; return -1; } if (used + n >= bsiz) { /* Allocate next buffer */ if ((b = msg_buf_alloc(msg, n + 1)) == NULL) return -1; bsiz = msg_buf_size(msg); used = 0; continue; } msg_buf_used(msg, n); total += n; used += n; b += n; h = h->sh_succ; } return total;}/** Encode a header or a list of headers */staticint msg_header_prepare(msg_mclass_t const *mc, int flags, msg_header_t *h, char *b, int bsiz){ msg_header_t *h0, *next; msg_hclass_t *hc; char const *s; int n, m, middle = 0; int compact, one_line_list, comma_list; assert(h); assert(h->sh_class); hc = h->sh_class; compact = MSG_IS_COMPACT(flags); one_line_list = compact || hc->hc_kind == msg_kind_apndlist; comma_list = one_line_list || MSG_IS_COMMA_LISTS(flags); for (h0 = h, n = 0; h; h = next) { next = h->sh_succ; if (!next || next->sh_class != hc || next->sh_data || !comma_list) next = NULL; if (!middle && hc->hc_name && hc->hc_name[0]) n += msg_header_name_e(b + n, bsiz >= n ? bsiz - n : 0, h, flags); if ((m = hc->hc_print(b + n, bsiz >= n ? bsiz - n : 0, h, flags)) < 0) { if (bsiz >= n + 64) m = 2 * (bsiz - n); else m = 128; } n += m; if (hc->hc_name) { /* Encode continuation */ if (!next) s = CRLF; else if (compact) s = ","; else if (one_line_list) s = ", "; else s = "," CRLF "\t"; m = strlen(s); if (bsiz <= n + m) { if (!next) return n + m; } else { strcpy(b + n, s); } n += m; } middle = 1; } if (bsiz > n) { /* XXX */ h0->sh_data = b, h0->sh_len = n; for (h = h0; h; h = next) { next = h->sh_succ; if (!next || next->sh_class != hc || next->sh_data || !comma_list) break; else next->sh_data = b, next->sh_len = 0; } } return n;}/** Encode a header. * * The function msg_header_e() encodes a header field in the buffer @a * b[]. The encoding includes its name and trailing CRLF. The function * returns the length of the encoding in bytes, excluding the final @c NUL. * The buffer @a b must be large enough for whole encoding, including the * final @c NUL. * * The @a flags parameter define how the encoding is done. If the flags * specify @c MSG_DO_COMPACT, the encoding is compact (short form with * minimal whitespace). */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -