forked from pool/libsoup
246 lines
6.3 KiB
Diff
246 lines
6.3 KiB
Diff
--- libsoup/soup-headers.c 2007-01-16 23:35:13.965088000 +0100
|
|
+++ libsoup/soup-headers.c.new 2007-01-16 23:37:11.845091000 +0100
|
|
@@ -18,80 +18,80 @@
|
|
int len,
|
|
GHashTable *dest)
|
|
{
|
|
- char *key = NULL, *val = NULL, *end = NULL;
|
|
- int offset = 0, lws = 0;
|
|
-
|
|
- key = strstr (str, "\r\n");
|
|
- key += 2;
|
|
-
|
|
- /* join continuation headers, using a comma */
|
|
- while ((key = strstr (key, "\r\n"))) {
|
|
- key += 2;
|
|
- offset = key - str;
|
|
-
|
|
- if (!*key)
|
|
- break;
|
|
-
|
|
- /* check if first character on the line is whitespace */
|
|
- if (*key == ' ' || *key == '\t') {
|
|
- key -= 2;
|
|
-
|
|
- /* eat any trailing space from the previous line*/
|
|
- while (key [-1] == ' ' || key [-1] == '\t') key--;
|
|
-
|
|
- /* count how many characters are whitespace */
|
|
- lws = strspn (key, " \t\r\n");
|
|
-
|
|
- /* if continuation line, replace whitespace with ", " */
|
|
- if (key [-1] != ':') {
|
|
- lws -= 2;
|
|
- key [0] = ',';
|
|
- key [1] = ' ';
|
|
- }
|
|
-
|
|
- g_memmove (key, &key [lws], len - offset - lws);
|
|
- }
|
|
- }
|
|
-
|
|
- key = str;
|
|
-
|
|
- /* set eos for header key and value and add to hashtable */
|
|
- while ((key = strstr (key, "\r\n"))) {
|
|
- GSList *exist_hdrs;
|
|
-
|
|
- /* set end of last val, or end of http reason phrase */
|
|
- key [0] = '\0';
|
|
- key += 2;
|
|
-
|
|
- if (!*key)
|
|
- break;
|
|
-
|
|
- val = strchr (key, ':'); /* find start of val */
|
|
-
|
|
- if (!val || val > strchr (key, '\r'))
|
|
+ const char *end = str + len;
|
|
+ const char *name_start, *name_end, *value_start, *value_end;
|
|
+ char *name, *value, *eol, *sol;
|
|
+ GSList *hdrs;
|
|
+
|
|
+ /* As per RFC 2616 section 19.3, we treat '\n' as the
|
|
+ * line terminator, and '\r', if it appears, merely as
|
|
+ * ignorable trailing whitespace.
|
|
+ */
|
|
+
|
|
+ /* Skip over the Request-Line / Status-Line */
|
|
+ value_end = memchr (str, '\n', len);
|
|
+ if (!value_end)
|
|
+ return FALSE;
|
|
+
|
|
+ while (value_end < end - 1) {
|
|
+ name_start = value_end + 1;
|
|
+ name_end = memchr (name_start, ':', end - name_start);
|
|
+ if (!name_end)
|
|
return FALSE;
|
|
|
|
- /* set end of key */
|
|
- val [0] = '\0';
|
|
-
|
|
- val++;
|
|
- val += strspn (val, " \t"); /* skip whitespace */
|
|
-
|
|
- /* find the end of the value */
|
|
- end = strstr (val, "\r\n");
|
|
- if (!end)
|
|
+ /* Find the end of the value; ie, an end-of-line that
|
|
+ * isn't followed by a continuation line.
|
|
+ */
|
|
+ value_end = memchr (name_start, '\n', end - name_start);
|
|
+ if (!value_end || value_end < name_end)
|
|
return FALSE;
|
|
+ while (value_end != end - 1 &&
|
|
+ (*(value_end + 1) == ' ' || *(value_end + 1) == '\t')) {
|
|
+ value_end = memchr (value_end + 1, '\n', end - value_end);
|
|
+ if (!value_end)
|
|
+ return FALSE;
|
|
+ }
|
|
|
|
- exist_hdrs = g_hash_table_lookup (dest, key);
|
|
- exist_hdrs = g_slist_append (exist_hdrs,
|
|
- g_strndup (val, end - val));
|
|
+ name = g_strndup (name_start, name_end - name_start);
|
|
|
|
- if (!exist_hdrs->next)
|
|
- g_hash_table_insert (dest, g_strdup (key), exist_hdrs);
|
|
+ value_start = name_end + 1;
|
|
+ while (value_start < value_end &&
|
|
+ (*value_start == ' ' || *value_start == '\t' ||
|
|
+ *value_start == '\r' || *value_start == '\n'))
|
|
+ value_start++;
|
|
+ value = g_strndup (value_start, value_end - value_start);
|
|
+
|
|
+ /* Collapse continuation lines inside value */
|
|
+ while ((eol = strchr (value, '\n'))) {
|
|
+ /* find start of next line */
|
|
+ sol = eol + 1;
|
|
+ while (*sol == ' ' || *sol == '\t')
|
|
+ sol++;
|
|
+
|
|
+ /* back up over trailing whitespace on current line */
|
|
+ while (eol[-1] == ' ' || eol[-1] == '\t' || eol[-1] == '\r')
|
|
+ eol--;
|
|
+
|
|
+ /* Delete all but one SP */
|
|
+ *eol = ' ';
|
|
+ g_memmove (eol + 1, sol, strlen (sol) + 1);
|
|
+ }
|
|
|
|
- key = end;
|
|
+ /* clip trailing whitespace */
|
|
+ eol = strchr (value, '\0');
|
|
+ while (eol > value &&
|
|
+ (eol[-1] == ' ' || eol[-1] == '\t' || eol[-1] == '\r'))
|
|
+ eol--;
|
|
+ *eol = '\0';
|
|
+
|
|
+ hdrs = g_hash_table_lookup (dest, name);
|
|
+ hdrs = g_slist_append (hdrs, value);
|
|
+ if (!hdrs->next)
|
|
+ g_hash_table_insert (dest, name, hdrs);
|
|
+ else
|
|
+ g_free (name);
|
|
}
|
|
-
|
|
+
|
|
return TRUE;
|
|
}
|
|
|
|
@@ -103,44 +103,72 @@
|
|
char **req_path,
|
|
SoupHttpVersion *ver)
|
|
{
|
|
- gulong http_major, http_minor;
|
|
- char *s1, *s2, *cr, *p;
|
|
+ const char *method, *method_end, *path, *path_end, *version, *headers;
|
|
+ int minor_version;
|
|
|
|
if (!str || !*str)
|
|
return FALSE;
|
|
|
|
- cr = memchr (str, '\r', len);
|
|
- if (!cr)
|
|
+ /* RFC 2616 4.1 "servers SHOULD ignore any empty line(s)
|
|
+ * received where a Request-Line is expected."
|
|
+ */
|
|
+ while (*str == '\r' || *str == '\n') {
|
|
+ str++;
|
|
+ len--;
|
|
+ }
|
|
+
|
|
+ /* RFC 2616 19.3 "[servers] SHOULD accept any amount of SP or
|
|
+ * HT characters between [Request-Line] fields"
|
|
+ */
|
|
+
|
|
+ method = method_end = str;
|
|
+ while (method_end < str + len && *method_end != ' ' && *method_end != '\t')
|
|
+ method_end++;
|
|
+ if (method_end >= str + len)
|
|
return FALSE;
|
|
|
|
- s1 = memchr (str, ' ', cr - str);
|
|
- if (!s1)
|
|
+ path = method_end;
|
|
+ while (path < str + len && (*path == ' ' || *path == '\t'))
|
|
+ path++;
|
|
+ if (path >= str + len)
|
|
return FALSE;
|
|
- s2 = memchr (s1 + 1, ' ', cr - (s1 + 1));
|
|
- if (!s2)
|
|
+
|
|
+ path_end = path;
|
|
+ while (path_end < str + len && *path_end != ' ' && *path_end != '\t')
|
|
+ path_end++;
|
|
+ if (path_end >= str + len)
|
|
return FALSE;
|
|
|
|
- if (strncmp (s2, " HTTP/", 6) != 0)
|
|
+ version = path_end;
|
|
+ while (version < str + len && (*version == ' ' || *version == '\t'))
|
|
+ version++;
|
|
+ if (version + 8 >= str + len)
|
|
return FALSE;
|
|
- http_major = strtoul (s2 + 6, &p, 10);
|
|
- if (*p != '.')
|
|
+
|
|
+ /* FIXME: we want SoupServer to return
|
|
+ * SOUP_STATUS_HTTP_VERSION_NOT_SUPPORTED here
|
|
+ */
|
|
+ if (strncmp (version, "HTTP/1.", 7) != 0)
|
|
return FALSE;
|
|
- http_minor = strtoul (p + 1, &p, 10);
|
|
- if (p != cr)
|
|
+ minor_version = version[7] - '0';
|
|
+ if (minor_version < 0 || minor_version > 1)
|
|
return FALSE;
|
|
|
|
- if (!soup_headers_parse (str, len, dest))
|
|
+ headers = version + 8;
|
|
+ if (headers < str + len && *headers == '\r')
|
|
+ headers++;
|
|
+ if (headers >= str + len || *headers != '\n')
|
|
return FALSE;
|
|
|
|
- *req_method = g_strndup (str, s1 - str);
|
|
- *req_path = g_strndup (s1 + 1, s2 - (s1 + 1));
|
|
+ if (!soup_headers_parse (str, len, dest))
|
|
+ return FALSE;
|
|
|
|
- if (ver) {
|
|
- if (http_major == 1 && http_minor == 1)
|
|
- *ver = SOUP_HTTP_1_1;
|
|
- else
|
|
- *ver = SOUP_HTTP_1_0;
|
|
- }
|
|
+ if (req_method)
|
|
+ *req_method = g_strndup (method, method_end - method);
|
|
+ if (req_path)
|
|
+ *req_path = g_strndup (path, path_end - path);
|
|
+ if (ver)
|
|
+ *ver = (minor_version == 0) ? SOUP_HTTP_1_0 : SOUP_HTTP_1_1;
|
|
|
|
return TRUE;
|
|
}
|