aboutsummaryrefslogtreecommitdiff
path: root/src/microhttpd/connection.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/microhttpd/connection.c')
-rw-r--r--src/microhttpd/connection.c299
1 files changed, 109 insertions, 190 deletions
diff --git a/src/microhttpd/connection.c b/src/microhttpd/connection.c
index 960c22db..16c5fb93 100644
--- a/src/microhttpd/connection.c
+++ b/src/microhttpd/connection.c
@@ -2829,146 +2829,6 @@ enum _MHD_ParseCookie
2829/** 2829/**
2830 * Parse the cookies string (see RFC 6265). 2830 * Parse the cookies string (see RFC 6265).
2831 * 2831 *
2832 * Parsing may fail if the string is not formed strictly as defined by RFC 6265.
2833 *
2834 * @param str the string to parse, without leading whitespaces
2835 * @param str_len the size of the @a str, not including mandatory
2836 * zero-termination
2837 * @param connection the connection to add parsed cookies
2838 * @return #MHD_PARSE_COOKIE_OK for success, error code otherwise
2839 */
2840static enum _MHD_ParseCookie
2841parse_cookies_string_strict (char *str,
2842 size_t str_len,
2843 struct MHD_Connection *connection)
2844{
2845 size_t i;
2846
2847 i = 0;
2848 while (i < str_len)
2849 {
2850 size_t name_start;
2851 size_t name_len;
2852 size_t value_start;
2853 size_t value_len;
2854 bool val_quoted;
2855 /* 'i' must point to the first char of cookie-name */
2856 name_start = i;
2857 /* Find the end of the cookie-name */
2858 do
2859 {
2860 const char l = str[i];
2861 if (('=' == l) || (' ' == l) || ('\t' == l) || ('"' == l) || (',' == l) ||
2862 (';' == l) || (0 == l))
2863 break;
2864 } while (str_len > ++i);
2865 if ((str_len == i) || ('=' != str[i]) || (name_start == i))
2866 return MHD_PARSE_COOKIE_MALFORMED; /* Incomplete cookie name */
2867 name_len = i - name_start;
2868 /* 'i' must point to the '=' char */
2869 mhd_assert ('=' == str[i]);
2870 i++;
2871 /* 'i' must point to the first char of cookie-value */
2872 if (str_len == i)
2873 {
2874 value_start = 0;
2875 value_len = 0;
2876#ifdef _DEBUG
2877 val_quoted = false; /* This assignment used in assert */
2878#endif
2879 }
2880 else
2881 {
2882 bool valid_cookie;
2883 val_quoted = ('"' == str[i]);
2884 if (val_quoted)
2885 i++;
2886 value_start = i;
2887 /* Find the end of the cookie-value */
2888 while (str_len > i)
2889 {
2890 const char l = str[i];
2891 if ((';' == l) || ('"' == l) || (' ' == l) || ('\t' == l)
2892 || (',' == l) || ('\\' == l) || (0 == l))
2893 break;
2894 i++;
2895 }
2896 value_len = i - value_start;
2897 if (val_quoted)
2898 {
2899 if ((str_len == i) || ('"' != str[i]))
2900 return MHD_PARSE_COOKIE_MALFORMED; /* Incomplete cookie value, no closing quote */
2901 i++;
2902 }
2903 if (str_len == i)
2904 valid_cookie = true;
2905 else if (';' == str[i])
2906 valid_cookie = true;
2907 else if ((' ' == str[i]) || ('\t' == str[i]))
2908 { /* Optional whitespace at the end of the string? */
2909 while (str_len > ++i)
2910 {
2911 if ((' ' != str[i]) && ('\t' != str[i]))
2912 break;
2913 }
2914 if (str_len == i)
2915 valid_cookie = true;
2916 else
2917 valid_cookie = false;
2918 }
2919 else
2920 valid_cookie = false;
2921
2922 if (! valid_cookie)
2923 return MHD_PARSE_COOKIE_MALFORMED; /* Garbage at the end of the cookie value */
2924 }
2925 mhd_assert (0 != name_len);
2926 str[name_start + name_len] = 0; /* Zero-terminate the name */
2927 if (0 != value_len)
2928 {
2929 mhd_assert (0 == str[i] || ';' == str[i]);
2930 mhd_assert (! val_quoted || ';' == str[i]);
2931 str[value_start + value_len] = 0; /* Zero-terminate the value */
2932 if (MHD_NO ==
2933 MHD_set_connection_value_n_nocheck_ (connection,
2934 MHD_COOKIE_KIND,
2935 str + name_start,
2936 name_len,
2937 str + value_start,
2938 value_len))
2939 return MHD_PARSE_COOKIE_NO_MEMORY;
2940 }
2941 else
2942 {
2943 if (MHD_NO ==
2944 MHD_set_connection_value_n_nocheck_ (connection,
2945 MHD_COOKIE_KIND,
2946 str + name_start,
2947 name_len,
2948 "",
2949 0))
2950 return MHD_PARSE_COOKIE_NO_MEMORY;
2951 }
2952 if (str_len > i)
2953 {
2954 mhd_assert (0 == str[i] || ';' == str[i]);
2955 mhd_assert (! val_quoted || ';' == str[i]);
2956 mhd_assert (';' != str[i] || val_quoted || 0 == value_len);
2957 i++;
2958 if (str_len == i)
2959 return MHD_PARSE_COOKIE_MALFORMED; /* No cookie name after semicolon */
2960 if (' ' != str[i])
2961 return MHD_PARSE_COOKIE_MALFORMED; /* No space after semicolon */
2962 i++;
2963 }
2964 }
2965 return MHD_PARSE_COOKIE_OK;
2966}
2967
2968
2969/**
2970 * Parse the cookies string (see RFC 6265).
2971 *
2972 * Try to parse the cookies string even if it is not strictly formed 2832 * Try to parse the cookies string even if it is not strictly formed
2973 * as specified by RFC 6265. 2833 * as specified by RFC 6265.
2974 * 2834 *
@@ -2979,12 +2839,22 @@ parse_cookies_string_strict (char *str,
2979 * @return #MHD_PARSE_COOKIE_OK for success, error code otherwise 2839 * @return #MHD_PARSE_COOKIE_OK for success, error code otherwise
2980 */ 2840 */
2981static enum _MHD_ParseCookie 2841static enum _MHD_ParseCookie
2982parse_cookies_string_lenient (char *str, 2842parse_cookies_string (char *str,
2983 size_t str_len, 2843 const size_t str_len,
2984 struct MHD_Connection *connection) 2844 struct MHD_Connection *connection)
2985{ 2845{
2986 size_t i; 2846 size_t i;
2987 bool non_strict; 2847 bool non_strict;
2848 /* Skip extra whitespaces and empty cookies */
2849 const bool allow_wsp_empty = (0 >= connection->daemon->strict_for_client);
2850 /* Allow whitespaces around '=' character */
2851 const bool wsp_around_eq = (0 > connection->daemon->strict_for_client);
2852 /* Allow whitespaces in quoted cookie value */
2853 const bool wsp_in_quoted = (0 >= connection->daemon->strict_for_client);
2854 /* Allow tab as space after semicolon between cookies */
2855 const bool tab_as_sp = (0 >= connection->daemon->strict_for_client);
2856 /* Allow no space after semicolon between cookies */
2857 const bool allow_no_space = (0 >= connection->daemon->strict_for_client);
2988 2858
2989 non_strict = false; 2859 non_strict = false;
2990 i = 0; 2860 i = 0;
@@ -2998,6 +2868,8 @@ parse_cookies_string_lenient (char *str,
2998 /* Skip any whitespaces and empty cookies */ 2868 /* Skip any whitespaces and empty cookies */
2999 while (' ' == str[i] || '\t' == str[i] || ';' == str[i]) 2869 while (' ' == str[i] || '\t' == str[i] || ';' == str[i])
3000 { 2870 {
2871 if (! allow_wsp_empty)
2872 return MHD_PARSE_COOKIE_MALFORMED;
3001 non_strict = true; 2873 non_strict = true;
3002 i++; 2874 i++;
3003 if (i == str_len) 2875 if (i == str_len)
@@ -3017,6 +2889,8 @@ parse_cookies_string_lenient (char *str,
3017 /* Skip any whitespaces */ 2889 /* Skip any whitespaces */
3018 while (str_len > i && (' ' == str[i] || '\t' == str[i])) 2890 while (str_len > i && (' ' == str[i] || '\t' == str[i]))
3019 { 2891 {
2892 if (! wsp_around_eq)
2893 return MHD_PARSE_COOKIE_MALFORMED;
3020 non_strict = true; 2894 non_strict = true;
3021 i++; 2895 i++;
3022 } 2896 }
@@ -3028,6 +2902,8 @@ parse_cookies_string_lenient (char *str,
3028 /* Skip any whitespaces */ 2902 /* Skip any whitespaces */
3029 while (str_len > i && (' ' == str[i] || '\t' == str[i])) 2903 while (str_len > i && (' ' == str[i] || '\t' == str[i]))
3030 { 2904 {
2905 if (! wsp_around_eq)
2906 return MHD_PARSE_COOKIE_MALFORMED;
3031 non_strict = true; 2907 non_strict = true;
3032 i++; 2908 i++;
3033 } 2909 }
@@ -3058,6 +2934,8 @@ parse_cookies_string_lenient (char *str,
3058 { 2934 {
3059 if (! val_quoted) 2935 if (! val_quoted)
3060 break; 2936 break;
2937 if (! wsp_in_quoted)
2938 return MHD_PARSE_COOKIE_MALFORMED;
3061 non_strict = true; 2939 non_strict = true;
3062 } 2940 }
3063 i++; 2941 i++;
@@ -3070,10 +2948,19 @@ parse_cookies_string_lenient (char *str,
3070 i++; 2948 i++;
3071 } 2949 }
3072 /* Skip any whitespaces */ 2950 /* Skip any whitespaces */
3073 while (str_len > i && (' ' == str[i] || '\t' == str[i])) 2951 if ((str_len > i) && ((' ' == str[i]) || ('\t' == str[i])))
3074 { 2952 {
3075 non_strict = true; 2953 do
3076 i++; 2954 {
2955 i++;
2956 } while (str_len > i && (' ' == str[i] || '\t' == str[i]));
2957 /* Whitespace at the end? */
2958 if (str_len > i)
2959 {
2960 if (! allow_wsp_empty)
2961 return MHD_PARSE_COOKIE_MALFORMED;
2962 non_strict = true;
2963 }
3077 } 2964 }
3078 if (str_len == i) 2965 if (str_len == i)
3079 valid_cookie = true; 2966 valid_cookie = true;
@@ -3118,11 +3005,29 @@ parse_cookies_string_lenient (char *str,
3118 mhd_assert (';' != str[i] || val_quoted || non_strict || 0 == value_len); 3005 mhd_assert (';' != str[i] || val_quoted || non_strict || 0 == value_len);
3119 i++; 3006 i++;
3120 if (str_len == i) 3007 if (str_len == i)
3121 non_strict = true; /* No cookie name after semicolon */ 3008 { /* No next cookie after semicolon */
3009 if (! allow_wsp_empty)
3010 return MHD_PARSE_COOKIE_MALFORMED;
3011 non_strict = true;
3012 }
3122 else if (' ' != str[i]) 3013 else if (' ' != str[i])
3123 non_strict = true; /* No space after semicolon */ 3014 {/* No space after semicolon */
3015 if (('\t' == str[i]) && tab_as_sp)
3016 i++;
3017 else if (! allow_no_space)
3018 return MHD_PARSE_COOKIE_MALFORMED;
3019 non_strict = true;
3020 }
3124 else 3021 else
3022 {
3125 i++; 3023 i++;
3024 if (str_len == i)
3025 {
3026 if (! allow_wsp_empty)
3027 return MHD_PARSE_COOKIE_MALFORMED;
3028 non_strict = true;
3029 }
3030 }
3126 } 3031 }
3127 } 3032 }
3128 return non_strict? MHD_PARSE_COOKIE_OK_LAX : MHD_PARSE_COOKIE_OK; 3033 return non_strict? MHD_PARSE_COOKIE_OK_LAX : MHD_PARSE_COOKIE_OK;
@@ -3141,8 +3046,10 @@ parse_cookie_header (struct MHD_Connection *connection)
3141 const char *hdr; 3046 const char *hdr;
3142 size_t hdr_len; 3047 size_t hdr_len;
3143 char *cpy; 3048 char *cpy;
3144 bool strict_parsing;
3145 size_t i; 3049 size_t i;
3050 enum _MHD_ParseCookie parse_res;
3051 const struct MHD_HTTP_Req_Header *const saved_tail =
3052 connection->rq.headers_received_tail;
3146 3053
3147 if (MHD_NO == 3054 if (MHD_NO ==
3148 MHD_lookup_connection_value_n (connection, 3055 MHD_lookup_connection_value_n (connection,
@@ -3159,25 +3066,61 @@ parse_cookie_header (struct MHD_Connection *connection)
3159 cpy = MHD_connection_alloc_memory_ (connection, 3066 cpy = MHD_connection_alloc_memory_ (connection,
3160 hdr_len + 1); 3067 hdr_len + 1);
3161 if (NULL == cpy) 3068 if (NULL == cpy)
3162 return MHD_PARSE_COOKIE_NO_MEMORY; 3069 parse_res = MHD_PARSE_COOKIE_NO_MEMORY;
3163 3070 else
3164 memcpy (cpy, 3071 {
3165 hdr, 3072 memcpy (cpy,
3166 hdr_len); 3073 hdr,
3167 cpy[hdr_len] = '\0'; 3074 hdr_len);
3075 cpy[hdr_len] = '\0';
3076
3077 i = 0;
3078 /* Skip all initial whitespaces */
3079 while (i < hdr_len && (' ' == cpy[i] || '\t' == cpy[i]))
3080 i++;
3168 3081
3169 /* TODO: add individual configuration */ 3082 parse_res = parse_cookies_string (cpy + i, hdr_len - i, connection);
3170 strict_parsing = (0 < connection->daemon->strict_for_client); 3083 }
3171 i = 0;
3172 /* Skip all initial whitespaces */
3173 while (i < hdr_len && (' ' == cpy[i] || '\t' == cpy[i]))
3174 i++;
3175 3084
3176 /* 'i' points to the first non-whitespace char or to the end of the string */ 3085 switch (parse_res)
3177 if (strict_parsing) 3086 {
3178 return parse_cookies_string_strict (cpy + i, hdr_len - i, connection); 3087 case MHD_PARSE_COOKIE_OK:
3088 break;
3089 case MHD_PARSE_COOKIE_OK_LAX:
3090#ifdef HAVE_MESSAGES
3091 if (saved_tail != connection->rq.headers_received_tail)
3092 MHD_DLOG (connection->daemon,
3093 _ ("The Cookie header has been parsed, but it is not fully "
3094 "compliant with the standard.\n"));
3095#endif /* HAVE_MESSAGES */
3096 break;
3097 case MHD_PARSE_COOKIE_MALFORMED:
3098#ifdef HAVE_MESSAGES
3099 if (saved_tail != connection->rq.headers_received_tail)
3100 MHD_DLOG (connection->daemon,
3101 _ ("The Cookie header has been only partially parsed as it "
3102 "contains malformed data.\n"));
3103 else
3104 MHD_DLOG (connection->daemon,
3105 _ ("The Cookie header has malformed data.\n"));
3106#endif /* HAVE_MESSAGES */
3107 break;
3108 case MHD_PARSE_COOKIE_NO_MEMORY:
3109#ifdef HAVE_MESSAGES
3110 MHD_DLOG (connection->daemon,
3111 _ ("Not enough memory in the connection pool to "
3112 "parse client cookies!\n"));
3113#endif /* HAVE_MESSAGES */
3114 break;
3115 default:
3116 mhd_assert (0);
3117 break;
3118 }
3119#ifndef HAVE_MESSAGES
3120 (void) saved_tail; /* Mute compiler warning */
3121#endif /* ! HAVE_MESSAGES */
3179 3122
3180 return parse_cookies_string_lenient (cpy + i, hdr_len - i, connection); 3123 return parse_res;
3181} 3124}
3182 3125
3183 3126
@@ -3946,37 +3889,13 @@ parse_connection_headers (struct MHD_Connection *connection)
3946 size_t val_len; 3889 size_t val_len;
3947 3890
3948#ifdef COOKIE_SUPPORT 3891#ifdef COOKIE_SUPPORT
3949 enum _MHD_ParseCookie cookie_res; 3892 if (MHD_PARSE_COOKIE_NO_MEMORY == parse_cookie_header (connection))
3950
3951 cookie_res = parse_cookie_header (connection);
3952 if (MHD_PARSE_COOKIE_NO_MEMORY == cookie_res)
3953 { 3893 {
3954#ifdef HAVE_MESSAGES
3955 MHD_DLOG (connection->daemon,
3956 _ ("Not enough memory in pool to parse cookies!\n"));
3957#endif
3958 transmit_error_response_static (connection, 3894 transmit_error_response_static (connection,
3959 MHD_HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE, 3895 MHD_HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE,
3960 REQUEST_TOO_BIG); 3896 REQUEST_TOO_BIG);
3961 return; 3897 return;
3962 } 3898 }
3963 else if (MHD_PARSE_COOKIE_OK_LAX == cookie_res)
3964 {
3965#ifdef HAVE_MESSAGES
3966 MHD_DLOG (connection->daemon,
3967 _ ("The Cookie header has been parsed, but is not fully "
3968 "compliant with the standard.\n"));
3969#endif
3970 (void) 0; /* Mute compiler warning */
3971 }
3972 else if (MHD_PARSE_COOKIE_MALFORMED == cookie_res)
3973 {
3974#ifdef HAVE_MESSAGES
3975 MHD_DLOG (connection->daemon,
3976 _ ("The Cookie header has malformed data.\n"));
3977#endif
3978 (void) 0; /* Mute compiler warning */
3979 }
3980#endif /* COOKIE_SUPPORT */ 3899#endif /* COOKIE_SUPPORT */
3981 if ( (1 <= connection->daemon->strict_for_client) && 3900 if ( (1 <= connection->daemon->strict_for_client) &&
3982 (MHD_IS_HTTP_VER_1_1_COMPAT (connection->rq.http_ver)) && 3901 (MHD_IS_HTTP_VER_1_1_COMPAT (connection->rq.http_ver)) &&