📄 msg_parser.c
字号:
* @relates msg_s * * When parsing a transport stream, only the first message in the stream is * created with msg_create(). The rest of the messages should be created * with msg_next() after previous message has been completely received and * parsed. * */msg_t *msg_next(msg_t *msg){ msg_t *next; unsigned n; if (msg && msg->m_next) { next = msg->m_next; msg->m_next = NULL; return next; } if ((n = msg_buf_committed(msg))) { if (msg_buf_move(next = msg_create(msg->m_class, msg->m_oflags), msg)) { msg_addr_copy(next, msg); return next; } /* How to indicate error? */ msg_destroy(next); } return NULL;}/** Set next message of the stream */int msg_set_next(msg_t *msg, msg_t *next){ if (!msg || (next && next->m_next)) return -1; if (msg->m_next && next) next->m_next = msg->m_next; msg->m_next = next; return 0;}/** Clear committed data */void msg_clear_committed(msg_t *msg){ if (msg) { unsigned n = msg_buf_committed(msg); if (n) msg_buf_used(msg, n); }}#if 0struct sigcomp_udvm;struct sigcomp_udvm *msg_get_udvm(msg_t *msg);struct sigcomp_udvm *msg_set_udvm(msg_t *msg, struct sigcomp_udvm *);/** Save UDVM. */struct sigcomp_udvm *msg_set_udvm(msg_t *msg, struct sigcomp_udvm *udvm){ struct sigcomp_udvm *prev = NULL; if (msg) { prev = msg->m_udvm; msg->m_udvm = udvm; } return prev;}/** Get saved UDVM */struct sigcomp_udvm *msg_get_udvm(msg_t *msg){ return msg ? msg->m_udvm : NULL;}#endif/** Mark message as complete. * * @relates msg_s */inlineunsigned msg_mark_as_complete(msg_t *msg, unsigned mask){ if (msg) { msg->m_streaming = 0; return msg->m_object->msg_flags |= mask | MSG_FLG_COMPLETE; } else { return 0; }}/** Return true if message is complete. * * @relates msg_s */int msg_is_complete(msg_t const *msg){ return msg && MSG_IS_COMPLETE(msg->m_object);}/** Return true if message has parsing errors. * * @relates msg_s*/int msg_has_error(msg_t const *msg){ return msg->m_object->msg_flags & MSG_FLG_ERROR;}/**Total size of message. * * @relates msg_s */unsigned msg_size(msg_t const *msg){ return msg ? msg->m_size : 0;}/** Set the maximum size of a message. * * @relates msg_s * * The function msg_maxsize() sets the maximum buffer size of a message. It * returns the previous maximum size. If the @a maxsize is 0, maximum size * is not set, but the current maximum size is returned. * * If the message size exceeds maxsize, msg_errno() returns ENOBUFS, * MSG_FLG_TOOLARGE and MSG_FLG_ERROR flags are set. */unsigned msg_maxsize(msg_t *msg, unsigned maxsize){ unsigned retval = 0; if (msg) { retval = msg->m_maxsize; if (maxsize) msg->m_maxsize = maxsize; } return retval;}/**Set the size of next fragment. * * @relates msg_s * * The function msg_streaming_size() sets the size of the message body for * streaming. */unsigned msg_streaming_size(msg_t *msg, unsigned ssize){ if (!msg) return -1; msg->m_ssize = ssize; return 0;}/**Allocate a list of external buffers. * * @relates msg_s * * The function msg_buf_external() allocates at most msg_n_fragments * external buffers for the message body. * * @return The function msg_buf_external() returns number of allocated * buffers, or -1 upon an error. */int msg_buf_external(msg_t *msg, unsigned N, unsigned blocksize){ msg_buffer_t *ext, *b, **bb; int i, I; assert(N <= 128 * 1024); if (msg == NULL) return -1; if (blocksize == 0) blocksize = msg_min_block; if (N == 0) N = blocksize; if (N > blocksize * msg_n_fragments) N = blocksize * msg_n_fragments; if (N > msg->m_ssize) N = msg->m_ssize; I = (N + blocksize - 1) / blocksize; assert(I <= msg_n_fragments); for (i = 0, bb = &ext; i < I; i++) { *bb = su_zalloc(msg_home(msg), sizeof **bb); if (!*bb) break; bb = &(*bb)->b_next; } if (i == I) for (b = ext, i = 0; b; b = b->b_next, i++) { b->b_data = su_alloc(msg_home(msg), b->b_size = blocksize); if (!b->b_data) break; } if (i == I) { /* Successful return */ for (bb = &msg->m_stream; *bb; bb = &(*bb)->b_next) ; *bb = ext; if (msg->m_ssize != MSG_SSIZE_MAX) for (b = ext; b; b = b->b_next) { if (msg->m_ssize < b->b_size) { b->b_size = msg->m_ssize; } msg->m_ssize -= b->b_size; } return i; } for (b = ext; b; b = ext) { ext = b->b_next; su_free(msg_home(msg), b->b_data); su_free(msg_home(msg), b); } return -1;}int msg_unref_external(msg_t *msg, msg_buffer_t *b){ if (msg && b) { su_free(msg_home(msg), b->b_data); su_free(msg_home(msg), b); return 0; } errno = EINVAL; return -1;}/* ====================================================================== *//* Parsing messages */static inline int extract_incomplete_chunks(msg_t *, int eos);static int extract_first(msg_t *, msg_pub_t *, char b[], int bsiz, int eos);static inline int extract_next(msg_t *, msg_pub_t *, char *, int, int, int);static int extract_header(msg_t *, msg_pub_t*, char b[], int bsiz, int eos, int copy);static msg_header_t *header_parse(msg_t *, msg_pub_t *, msg_href_t const *, char s[], int slen, int copy_buffer);static inline intextract_trailers(msg_t *msg, msg_pub_t *mo, char *b, int bsiz, int eos, int copy);/** Calculate length of line ending (0, 1 or 2) */#define CRLF_TEST(b) ((b)[0] == '\r' ? ((b)[1] == '\n') + 1 : (b)[0] =='\n')static inline voidappend_parsed(msg_t *msg, msg_pub_t *mo, msg_header_t **hh, msg_header_t *h, int always_into_chain);/**Extract and parse a message from internal buffer. * * @relates msg_s * * This function parses the internal buffer and adds the parsed fragments to * the message object. It marks the successfully parsed data as extracted. * * @param msg message to be parsed * * @retval positive if a complete message was parsed * @retval 0 if message was incomplete * @retval negative if an error occurred */int msg_extract(msg_t *msg){ msg_pub_t *mo = msg_object(msg); msg_mclass_t const *mc; char *b; int m, bsiz, eos; if (!msg || !msg->m_buffer->mb_data) return -1; assert(mo); mc = msg->m_class; mo = msg->m_object; eos = msg->m_buffer->mb_eos; if (msg->m_chunk) { m = extract_incomplete_chunks(msg, eos); if (m < 1 || MSG_IS_COMPLETE(mo)) return m; } if (mo->msg_flags & MSG_FLG_TRAILERS) msg_set_streaming(msg, 0); if (msg->m_buffer->mb_used + msg->m_buffer->mb_commit == msg->m_buffer->mb_size) /* Why? When? */ return 0; assert(msg->m_buffer->mb_used + msg->m_buffer->mb_commit < msg->m_buffer->mb_size); m = 0; b = msg->m_buffer->mb_data + msg->m_buffer->mb_used; bsiz = msg->m_buffer->mb_commit; b[bsiz] = '\0'; while (msg->m_buffer->mb_commit > 0) { int flags = mo->msg_flags; int copy = MSG_IS_EXTRACT_COPY(flags); if (flags & MSG_FLG_COMPLETE) break; if (flags & MSG_FLG_TRAILERS) m = extract_trailers(msg, mo, b, bsiz, eos, copy); else if (flags & MSG_FLG_BODY) m = mc->mc_extract_body(msg, mo, b, bsiz, eos); else if (flags & MSG_FLG_HEADERS) m = extract_next(msg, mo, b, bsiz, eos, copy); else m = extract_first(msg, mo, b, bsiz, eos); if (m <= 0 || msg->m_chunk) break; b += m; bsiz -= m; msg_buf_used(msg, m); } if (eos && bsiz == 0) msg_mark_as_complete(msg, 0); if (m < 0 || (mo->msg_flags & MSG_FLG_ERROR)) { msg_mark_as_complete(msg, MSG_FLG_ERROR); return -1; } else if (!MSG_IS_COMPLETE(mo)) return 0; else if (!(mo->msg_flags & MSG_FLG_HEADERS)) { msg_mark_as_complete(msg, MSG_FLG_ERROR); return -1; } else return 1;}staticint extract_first(msg_t *msg, msg_pub_t *mo, char b[], int bsiz, int eos){ /* First line */ int k, l, m, n, crlf, xtra; msg_header_t *h, **hh; msg_href_t const *hr; msg_mclass_t const *mc = msg->m_class; for (k = 0; IS_LWS(b[k]); k++) /* Skip whitespace */ ; if (!b[k]) return k; /* If first token contains no /, this is request, otherwise status line */ l = span_token(b + k) + k; if (b[l] != '/') hr = mc->mc_request; else hr = mc->mc_status; n = span_non_crlf(b + l) + l; if (!b[n]) return eos ? -1 : 0; crlf = CRLF_TEST(b + n); for (m = n + crlf; IS_WS(b[m]); m++) ; /* In order to skip possible whitespace after first line, we don't parse first line until first non-ws char from next one has been received */ if (!b[m] && !eos) return 0; xtra = MSG_IS_EXTRACT_COPY(mo->msg_flags) ? n + 1 - k : 0; if (!(h = msg_header_alloc(msg_home(msg), hr->hr_class, xtra))) return -1; if (xtra) { char *bb = memcpy(MSG_HEADER_DATA(h), b, xtra - 1); h->sh_data = b, h->sh_len = n + crlf; b = bb; n = xtra - 1; } else { b = b + k; n = n - k; } b[n] = 0; if (hr->hr_class->hc_parse(msg_home(msg), h, b, n) < 0) return -1; assert(hr->hr_offset); hh = (msg_header_t**)((char *)mo + hr->hr_offset); append_parsed(msg, mo, hh, h, 1); mo->msg_flags |= MSG_FLG_HEADERS; return m;}/* Extract header or message body */static inline intextract_next(msg_t *msg, msg_pub_t *mo, char *b, int bsiz, int eos, int copy){ if (IS_CRLF(b[0])) return msg->m_class->mc_extract_body(msg, mo, b, bsiz, eos); else return extract_header(msg, mo, b, bsiz, eos, copy);}/** Extract a header. */int msg_extract_header(msg_t *msg, msg_pub_t *mo, char b[], int bsiz, int eos){ return extract_header(msg, mo, b, bsiz, eos, 0);}/** Extract a header from buffer @a b. */staticintextract_header(msg_t *msg, msg_pub_t *mo, char *b, int bsiz, int eos, int copy_buffer){ int len, n = 0, m, crlf = 0; int name_len = 0, name_len_set = 0; int error = 0, xtra; msg_header_t *h; msg_href_t const *hr; msg_mclass_t const *mc = msg->m_class; hr = msg_find_hclass(mc, b, &n); /* Get header name */ error = n == 0; if (hr == NULL) /* Panic */ return -1; xtra = span_ws(b + n); /* Find next crlf which is not followed by whitespace */ do { n += xtra + crlf; if (!eos && bsiz == n) return 0; m = span_non_crlf(b + n); if (!name_len_set && m) name_len = n, name_len_set = 1; /* First non-ws after COLON */ n += m; crlf = CRLF_TEST(b + n); xtra = span_ws(b + n + crlf); } while (xtra); if (!eos && bsiz == n + crlf) return 0; if (hr->hr_class->hc_hash == msg_unknown_hash) name_len = 0, name_len_set = 1; if (error) { msg->m_extract_err |= hr->hr_flags; if (hr->hr_class->hc_critical) mo->msg_flags |= MSG_FLG_ERROR; hr = mc->mc_error; copy_buffer = 1; h = header_parse(msg, mo, hr, NULL, 0, 0); } else { if (!name_len_set) /* Empty header - nothing but name, COLON and LWS */ name_len = n; else /* Strip extra whitespace at the end of header */ while (n > name_len && IS_LWS(b[n - 1])) n--, crlf++; h = header_parse(msg, mo, hr, b + name_len, n - name_len, copy_buffer); } if (h == NULL) return -1; len = n + crlf; /* * If the header contains multiple header fields, set the pointer to the * encodeded data correctly */ while (h) { if (copy_buffer) h->sh_data = b, h->sh_len = len; b += len, len = 0; if (h->sh_succ) assert(&h->sh_succ == h->sh_succ->sh_prev); h = h->sh_next; } return n + crlf;}staticmsg_header_t *header_parse(msg_t *msg, msg_pub_t *mo, msg_href_t const *hr, char s[], int slen, int copy_buffer){ su_home_t *home = msg_home(msg); msg_header_t *h, **hh; msg_header_t *h0, *h_next; msg_hclass_t *hc = hr->hr_class; int n; int add_to_list, clear = 0; hh = (msg_header_t **)((char *)mo + hr->hr_offset); add_to_list = (hc->hc_kind == msg_kind_list && !copy_buffer && *hh); if (add_to_list) h = *hh;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -