示例#1
0
/* See section 4.2 of RFC 2616 for header format. */
int http_parse_header(struct http_header **result, const char *header)
{
    const char *p, *q;
    size_t value_len, value_offset;
    struct http_header *node, **prev;

    *result = NULL;
    prev = result;

    p = header;
    while (*p != '\0' && !is_crlf(p)) {
        /* Get the field name. */
        q = p;
        while (*q != '\0' && is_token_char(*q))
            q++;
        if (*q != ':') {
            http_header_free(*result);
            return 400;
        }

        node = (struct http_header *) safe_malloc(sizeof(*node));
        node->name = mkstr(p, q);
        node->value = NULL;
        node->next = NULL;
        value_len = 0;
        value_offset = 0;

        /* Copy the header field value until we hit a CRLF. */
        p = q + 1;
        p = skip_lws(p);
        for (;;) {
            q = p;
            while (*q != '\0' && !is_space_char(*q) && !is_crlf(q)) {
                /* Section 2.2 of RFC 2616 disallows control characters. */
                if (iscntrl((int) (unsigned char) *q)) {
                    http_header_node_free(node);
                    return 400;
                }
                q++;
            }
            strbuf_append(&node->value, &value_len, &value_offset, p, q - p);
            p = skip_lws(q);
            if (is_crlf(p))
                break;
            /* Replace LWS with a single space. */
            strbuf_append_str(&node->value, &value_len, &value_offset, " ");
        }
        *prev = node;
        prev = &node->next;

        p = skip_crlf(p);
    }

    return 0;
}
示例#2
0
/**
 * Parse a list of elements (#rule in [2.1]).
 */
bool parse_list(const char *s, regex_t *preg, unsigned int n, unsigned int m,
    void (*callback)(const char *s, regmatch_t pmatch[]))
{
  int r;
  unsigned int items = 0;
  regmatch_t pmatch[20];

  do {
    r = regexec(preg, s, 20, pmatch, 0);
    if (r) {
      if (html)
        printf("<li class='error'>");
      printf("    Failed to match list item %i\n", items + 1);
      if (html)
        printf("</li>\n");
      return false;
    }

    if (callback)
      callback(s, pmatch);
    items++;

    s += pmatch[0].rm_eo;
    s = skip_lws(s);
    if (*s == 0)
      break;
    if (*s != ',') {
      if (html)
        printf("<li class='error'>");
      printf("    Expecting , after list item %i\n", items);
      if (html)
        printf("</li>\n");
      return false;
    }
    while (*s == ',')
      s = skip_lws(s + 1);
  } while (*s != 0);

  if (items < n || m < items) {
    if (html)
      printf("<li class='error'>");
    printf("    %i items in list, but there should be ", items);
    if (m == UINT_MAX)
      printf("at least %i\n", n);
    else
      printf("between %i and %i\n", n, m);
    if (html)
      printf("</li>\n");
    return false;
  }

  return true;
}
示例#3
0
static void
mangle_line (const char * line, const char * prefix)
{
  const char * scan = (skip_name (line));
  scan = (skip_lws (scan));
  scan = (skip_fixed (scan, '('));
  scan = (skip_lws (scan));
  scan = (skip_fixed (scan, '"'));
  write_string (prefix);
  write_string (scan);
  write_char ('\n');
  fflush (stdout);
}
示例#4
0
/* Scan a cookie parameter */
static issize_t set_cookie_scanner(char *s)
{
  char *rest;

#define LOOKING_AT(s, what) \
  (su_casenmatch((s), what, strlen(what)) && (rest = s + strlen(what)))

  /* Special cases from Netscape spec */
  if (LOOKING_AT(s, "expires=")) {
    msg_time_t value;
    msg_date_d((char const **)&rest, &value);
  } else if (LOOKING_AT(s, "path=/")) {
    for (;;) {
      rest += span_unreserved(rest);
      if (*rest != '/')
	break;
      rest++;
    }
  } else {
    return msg_attribute_value_scanner(s);
  }
#undef LOOKING_AT

  if (IS_LWS(*rest)) {
    *rest++ = '\0'; skip_lws(&rest);
  }

  return rest - s;
}
示例#5
0
/** Decode (parse) a Cookie header */
issize_t http_cookie_d(su_home_t *home, msg_header_t *h, char *s, isize_t slen)
{
  http_cookie_t *c = (http_cookie_t *)h;

  assert(h); assert(sizeof(*h));

  for (;*s;) {
    /* Ignore empty entries (comma-whitespace) */
    if (*s == ',') { *s++ = '\0'; skip_lws(&s); continue; }

    if (msg_any_list_d(home, &s, (msg_param_t **)&c->c_params,
		       cookie_scanner, ';') == -1)
      return -1;

    if (*s != '\0' && *s != ',')
      return -1;

    if (!c->c_params)
      return -1;
  }

  http_cookie_update(c);

  return 0;
}
示例#6
0
issize_t sip_refer_to_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
{
  issize_t retval;
  sip_refer_to_t *r = (sip_refer_to_t *)h;

  retval = sip_name_addr_d(home, &s,
			   &r->r_display,
			   r->r_url,
			   &r->r_params,
			   NULL);
  if (retval < 0)
    return retval;

  if (*s == '?' && !r->r_display && !r->r_url->url_headers) {
    /* Missing <> around URL */
    *s++ = '\0';
    r->r_url->url_headers = s;
    s += strcspn(s, " \t;,");
    if (IS_LWS(*s))
      *s++ = '\0', skip_lws(&s);
    if (*s)
      return -1;
    r->r_display = s;	/* Put empty string in display so that we encode using <> */
  }
  else if (*s)
    return -1;

  return retval;
}
示例#7
0
/** Decode (parse) Set-Cookie header */
issize_t http_set_cookie_d(su_home_t *home, msg_header_t *h, char *s, isize_t slen)
{
  msg_header_t **hh = &h->sh_succ, *h0 = h;
  http_set_cookie_t *sc = (http_set_cookie_t *)h;
  msg_param_t *params;

  assert(h); assert(sizeof(*h));

  for (;*s;) {
    /* Ignore empty entries (comma-whitespace) */
    if (*s == ',') { *s++ = '\0'; skip_lws(&s); continue; }

    if (!h) {      /* Allocate next header structure */
      if (!(h = msg_header_alloc(home, h0->sh_class, 0)))
	return -1;
      *hh = h; h->sh_prev = hh; hh = &h->sh_succ;
      sc = sc->sc_next = (http_set_cookie_t *)h;
    }

    /* "Set-Cookie:" 1#(NAME "=" VALUE *(";" cookie-av))) */
    params = su_zalloc(home, MSG_PARAMS_NUM(1) * sizeof(msg_param_t));
    if (!params)
      return -1;

    params[0] = s, sc->sc_params = params;
    s += strcspn(s, ",;" LWS);

    if (*s) {
      *s++ = '\0';
      skip_lws(&s);
      if (*s && msg_any_list_d(home, &s, (msg_param_t **)&sc->sc_params,
			       set_cookie_scanner, ';') == -1)
	return -1;
    }

    if (*s != '\0' && *s != ',')
      return -1;

    if (sc->sc_params)
      http_set_cookie_update(sc);

    h = NULL;
  }

  return 0;
}
示例#8
0
/* Scan a cookie parameter */
static issize_t cookie_scanner(char *s)
{
  char *p = s;
  size_t tlen;

  skip_token(&s);

  if (s == p)		/* invalid parameter name */
    return -1;

  tlen = s - p;

  if (IS_LWS(*s)) { *s++ = '\0'; skip_lws(&s); }

  if (*s == '=') {
    char *v;
    s++;
    skip_lws(&s);

    v = s;

    /* get value */
    if (*s == '"') {
      size_t qlen = span_quoted(s);
      if (!qlen)
	return -1;
      s += qlen;
    }
    else {
      s += strcspn(s, ",;" LWS);
      if (s == v)
	return -1;
    }

    if (p + tlen + 1 != v) {
      memmove(p + tlen + 1, v, s - v);
      p[tlen] = '=';
      p[tlen + 1 + (s - v)] = '\0';
    }
  }

  if (IS_LWS(*s)) { *s++ = '\0'; skip_lws(&s); }

  return s - p;
}
示例#9
0
/**
 * Callback for received header data.
 */
size_t header_callback(char *ptr, size_t msize, size_t nmemb, void *stream)
{
  const size_t size = msize * nmemb;
  char s[400], *name, *value;

  UNUSED(stream);

  printf(html ? "<li><code>" : "* ");
  print(ptr, size);
  printf(html ? "</code><ul>" : "\n");

  if (size < 2 || ptr[size - 2] != 13 || ptr[size - 1] != 10) {
    lookup("notcrlf");
    if (html)
      printf("</ul></li>\n");
    return size;
  }
  if (sizeof s <= size) {
    lookup("headertoolong");
    if (html)
      printf("</ul></li>\n");
    return size;
  }
  strncpy(s, ptr, size);
  s[size - 2] = 0;

  name = s;
  value = strchr(s, ':');

  if (s[0] == 0) {
    /* empty header indicates end of headers */
    lookup("endofheaders");
    if (html)
      printf("</ul></li>\n");
    return 0;

  } else if (start) {
    /* Status-Line [6.1] */
    check_status_line(s);
    start = false;

  } else if (!value) {
    lookup("missingcolon");

  } else {
    *value = 0;
    value++;

    check_header(name, skip_lws(value));
  }

  if (html)
    printf("</ul></li>\n");
  return size;
}
示例#10
0
issize_t sip_rack_d(su_home_t *home, sip_header_t *h, char *s, isize_t slen)
{
  sip_rack_t *ra = h->sh_rack;

  ra->ra_response = strtoul(s, &s, 10);

  if (IS_LWS(*s)) {
    skip_lws(&s);
    ra->ra_cseq = strtoul(s, &s, 10);

    if (IS_LWS(*s)) {
      skip_lws(&s);
      if ((ra->ra_method = sip_method_d(&s, &ra->ra_method_name)) >= 0) {
	return 0;
      }
    }
  }

  return -1;
}
示例#11
0
/** Parse SIP <word "@" word> construct used in @CallID. */
char *sip_word_at_word_d(char **ss)
{
  char *rv = *ss, *s0 = *ss;

  skip_word(ss);
  if (s0 == *ss)
    return NULL;
  if (**ss == '@') {
    (*ss)++;
    s0 = *ss;
    skip_word(ss);
    if (s0 == *ss)
      return NULL;
  }
  if (IS_LWS(**ss))
    (*ss)++;
  skip_lws(ss);

  return rv;
}
示例#12
0
static GHashTable *
parse_param_list (const char *header, char delim)
{
	GHashTable *params;
	GSList *list, *iter;
	char *item, *eq, *name_end, *value;
	gboolean override;

	params = g_hash_table_new_full (soup_str_case_hash, 
					soup_str_case_equal,
					g_free, NULL);

	list = parse_list (header, delim);
	for (iter = list; iter; iter = iter->next) {
		item = iter->data;
		override = FALSE;

		eq = strchr (item, '=');
		if (eq) {
			name_end = (char *)unskip_lws (eq, item);
			if (name_end == item) {
				/* That's no good... */
				g_free (item);
				continue;
			}

			*name_end = '\0';

			value = (char *)skip_lws (eq + 1);

			if (name_end[-1] == '*' && name_end > item + 1) {
				name_end[-1] = '\0';
				if (!decode_rfc5987 (value)) {
					g_free (item);
					continue;
				}
				override = TRUE;
			} else if (*value == '"')
示例#13
0
文件: http.c 项目: aosm/wget
/* Parse the `Content-Range' header and extract the information it
   contains.  Returns 1 if successful, -1 otherwise.  */
static int
http_process_range (const char *hdr, void *arg)
{
  struct http_process_range_closure *closure
    = (struct http_process_range_closure *)arg;
  long num;

  /* Certain versions of Nutscape proxy server send out
     `Content-Length' without "bytes" specifier, which is a breach of
     RFC2068 (as well as the HTTP/1.1 draft which was current at the
     time).  But hell, I must support it...  */
  if (!strncasecmp (hdr, "bytes", 5))
    {
      hdr += 5;
      hdr += skip_lws (hdr);
      if (!*hdr)
	return 0;
    }
  if (!ISDIGIT (*hdr))
    return 0;
  for (num = 0; ISDIGIT (*hdr); hdr++)
    num = 10 * num + (*hdr - '0');
  if (*hdr != '-' || !ISDIGIT (*(hdr + 1)))
    return 0;
  closure->first_byte_pos = num;
  ++hdr;
  for (num = 0; ISDIGIT (*hdr); hdr++)
    num = 10 * num + (*hdr - '0');
  if (*hdr != '/' || !ISDIGIT (*(hdr + 1)))
    return 0;
  closure->last_byte_pos = num;
  ++hdr;
  for (num = 0; ISDIGIT (*hdr); hdr++)
    num = 10 * num + (*hdr - '0');
  closure->entity_length = num;
  return 1;
}
示例#14
0
/** Decode transport */
issize_t sip_transport_d(char **ss, char const **ttransport)
{
  char const *transport;
  char *pn, *pv, *pt;
  size_t pn_len, pv_len, pt_len;
  char *s = *ss;

#define TRANSPORT_MATCH(t) \
  (su_casenmatch(s + 7, t + 7, (sizeof t) - 8) && \
   (!s[sizeof(t) - 1] || IS_LWS(s[sizeof(t) - 1]))	\
   && (transport = t, s += sizeof(t) - 1))

  if (!su_casenmatch(s, "SIP/2.0", 7) ||
      (!TRANSPORT_MATCH(sip_transport_udp) &&
       !TRANSPORT_MATCH(sip_transport_tcp) &&
       !TRANSPORT_MATCH(sip_transport_sctp) &&
       !TRANSPORT_MATCH(sip_transport_ws) &&
       !TRANSPORT_MATCH(sip_transport_wss) &&
       !TRANSPORT_MATCH(sip_transport_tls))) {
    /* Protocol name */
    transport = pn = s;
    skip_token(&s);
    pn_len = s - pn;
    skip_lws(&s);
    if (pn_len == 0 || *s++ != '/') return -1;
    skip_lws(&s);

    /* Protocol version */
    pv = s;
    skip_token(&s);
    pv_len = s - pv;
    skip_lws(&s);
    if (pv_len == 0 || *s++ != '/') return -1;
    skip_lws(&s);

    /* Transport protocol */
    pt = s;
    skip_token(&s);
    pt_len = s - pt;
    if (pt_len == 0) return -1;

    /* Remove whitespace between protocol name and version */
    if (pn + pn_len + 1 != pv) {
      pn[pn_len] = '/';
      pv = memmove(pn + pn_len + 1, pv, pv_len);
    }

    /* Remove whitespace between protocol version and transport */
    if (pv + pv_len + 1 != pt) {
      pv[pv_len] = '/';
      pt = memmove(pv + pv_len + 1, pt, pt_len);
      pt[pt_len] = '\0';

      /* extra whitespace? */
      if (su_casematch(transport, sip_transport_udp))
	transport = sip_transport_udp;
      else if (su_casematch(transport, sip_transport_tcp))
	transport = sip_transport_tcp;
      else if (su_casematch(transport, sip_transport_sctp))
	transport = sip_transport_sctp;
      else if (su_casematch(transport, sip_transport_ws))
	transport = sip_transport_ws;
      else if (su_casematch(transport, sip_transport_wss))
	transport = sip_transport_wss;
      else if (su_casematch(transport, sip_transport_tls))
	transport = sip_transport_tls;
    }
  }

  if (IS_LWS(*s)) { *s++ = '\0'; skip_lws(&s); }
  *ss = s;
  *ttransport = transport;
  return 0;
}
示例#15
0
/* http://wp.netscape.com/newsref/std/cookie_spec.html */
void header_set_cookie(const char *s)
{
  bool ok = true;
  int r;
  const char *semi = strchr(s, ';');
  const char *s2;
  struct tm tm;
  double diff;
  time_t time0, time1;
  regmatch_t pmatch[20];

  if (semi)
    s2 = strndup(s, semi - s);
  else
    s2 = s;

  r = regexec(&re_cookie_nameval, s2, 0, 0, 0);
  if (r) {
    lookup("cookiebadnameval");
    ok = false;
  }

  if (!semi)
    return;

  s = skip_lws(semi + 1);

  while (*s) {
    semi = strchr(s, ';');
    if (semi)
      s2 = strndup(s, semi - s);
    else
      s2 = s;

    if (strncasecmp(s2, "expires=", 8) == 0) {
      s2 += 8;
      r = regexec(&re_cookie_expires, s2, 20, pmatch, 0);
      if (r == 0) {
        tm.tm_mday = atoi(s2 + pmatch[2].rm_so);
        tm.tm_mon = month(s2 + pmatch[3].rm_so);
        tm.tm_year = atoi(s2 + pmatch[4].rm_so) - 1900;
        tm.tm_hour = atoi(s2 + pmatch[5].rm_so);
        tm.tm_min = atoi(s2 + pmatch[6].rm_so);
        tm.tm_sec = atoi(s2 + pmatch[7].rm_so);

        time0 = time(0);
        time1 = mktime_from_utc(&tm);

        diff = difftime(time0, time1);
        if (10 < diff) {
          lookup("cookiepastdate");
          ok = false;
        }
      } else {
        lookup("cookiebaddate");
        ok = false;
      }
    } else if (strncasecmp(s2, "domain=", 7) == 0) {
    } else if (strncasecmp(s2, "path=", 5) == 0) {
      if (s2[5] != '/') {
        lookup("cookiebadpath");
        ok = false;
      }
    } else if (strcasecmp(s, "secure") == 0) {
    } else {
      if (html)
        printf("<li class='warning'>");
      printf("    Set-Cookie field '%s':\n", s2);
      if (html)
        printf("</li>\n");
      lookup("cookieunknownfield");
      ok = false;
    }

    if (semi)
      s = skip_lws(semi + 1);
    else
      break;
  }

  if (ok)
    lookup("ok");
}
示例#16
0
/**
 * soup_header_parse_quality_list:
 * @header: a header value
 * @unacceptable: (out) (allow-none) (transfer full) (element-type utf8): on
 * return, will contain a list of unacceptable values
 *
 * Parses a header whose content is a list of items with optional
 * "qvalue"s (eg, Accept, Accept-Charset, Accept-Encoding,
 * Accept-Language, TE).
 *
 * If @unacceptable is not %NULL, then on return, it will contain the
 * items with qvalue 0. Either way, those items will be removed from
 * the main list.
 *
 * Return value: (transfer full) (element-type utf8): a #GSList of
 * acceptable values (as allocated strings), highest-qvalue first.
 **/
GSList *
soup_header_parse_quality_list (const char *header, GSList **unacceptable)
{
	GSList *unsorted;
	QualityItem *array;
	GSList *sorted, *iter;
	char *item, *semi;
	const char *param, *equal, *value;
	double qval;
	int n;

	g_return_val_if_fail (header != NULL, NULL);

	if (unacceptable)
		*unacceptable = NULL;

	unsorted = soup_header_parse_list (header);
	array = g_new0 (QualityItem, g_slist_length (unsorted));
	for (iter = unsorted, n = 0; iter; iter = iter->next) {
		item = iter->data;
		qval = 1.0;
		for (semi = strchr (item, ';'); semi; semi = strchr (semi + 1, ';')) {
			param = skip_lws (semi + 1);
			if (*param != 'q')
				continue;
			equal = skip_lws (param + 1);
			if (!equal || *equal != '=')
				continue;
			value = skip_lws (equal + 1);
			if (!value)
				continue;

			if (value[0] != '0' && value[0] != '1')
				continue;
			qval = (double)(value[0] - '0');
			if (value[0] == '0' && value[1] == '.') {
				if (g_ascii_isdigit (value[2])) {
					qval += (double)(value[2] - '0') / 10;
					if (g_ascii_isdigit (value[3])) {
						qval += (double)(value[3] - '0') / 100;
						if (g_ascii_isdigit (value[4]))
							qval += (double)(value[4] - '0') / 1000;
					}
				}
			}

			*semi = '\0';
			break;
		}

		if (qval == 0.0) {
			if (unacceptable) {
				*unacceptable = g_slist_prepend (*unacceptable,
								 item);
			}
		} else {
			array[n].item = item;
			array[n].qval = qval;
			n++;
		}
	}
	g_slist_free (unsorted);

	qsort (array, n, sizeof (QualityItem), sort_by_qval);
	sorted = NULL;
	while (n--)
		sorted = g_slist_prepend (sorted, array[n].item);
	g_free (array);

	return sorted;
}