Skip to content

Commit a1eb4e5

Browse files
committed
ext/standard/mail.c: Refactor mail additional header build code
1 parent 51d6e1e commit a1eb4e5

File tree

1 file changed

+71
-92
lines changed

1 file changed

+71
-92
lines changed

ext/standard/mail.c

Lines changed: 71 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,9 @@
5656

5757
extern zend_long php_getuid(void);
5858

59-
static php_mail_header_value_error_type php_mail_build_headers_check_field_value(zval *val)
59+
static php_mail_header_value_error_type php_mail_build_headers_check_field_value(const zend_string *value)
6060
{
6161
size_t len = 0;
62-
zend_string *value = Z_STR_P(val);
6362

6463
/* https://tools.ietf.org/html/rfc2822#section-2.2.1 */
6564
/* https://tools.ietf.org/html/rfc2822#section-2.2.3 */
@@ -100,74 +99,55 @@ static php_mail_header_value_error_type php_mail_build_headers_check_field_value
10099
return NO_HEADER_ERROR;
101100
}
102101

103-
104-
static bool php_mail_build_headers_check_field_name(zend_string *key)
102+
static bool php_mail_build_headers_check_field_name(const zend_string *key)
105103
{
106104
size_t len = 0;
107105

108106
/* https://tools.ietf.org/html/rfc2822#section-2.2 */
109-
while (len < key->len) {
110-
if (*(key->val+len) < 33 || *(key->val+len) > 126 || *(key->val+len) == ':') {
111-
return FAILURE;
107+
while (len < ZSTR_LEN(key)) {
108+
if (*(ZSTR_VAL(key)+len) < 33 || *(ZSTR_VAL(key)+len) > 126 || *(ZSTR_VAL(key)+len) == ':') {
109+
return false;
112110
}
113111
len++;
114112
}
115-
return SUCCESS;
113+
return true;
116114
}
117115

118-
119-
static void php_mail_build_headers_elems(smart_str *s, zend_string *key, zval *val);
120-
121-
static void php_mail_build_headers_elem(smart_str *s, zend_string *key, zval *val)
116+
static void php_mail_build_headers_elem(smart_str *s, const zend_string *key, const zend_string *val)
122117
{
123-
switch(Z_TYPE_P(val)) {
124-
case IS_STRING:
125-
if (php_mail_build_headers_check_field_name(key) != SUCCESS) {
126-
zend_value_error("Header name \"%s\" contains invalid characters", ZSTR_VAL(key));
127-
return;
128-
}
129-
130-
php_mail_header_value_error_type error_type = php_mail_build_headers_check_field_value(val);
131-
switch (error_type) {
132-
case NO_HEADER_ERROR:
133-
break;
134-
case CONTAINS_LF_ONLY:
135-
zend_value_error("Header \"%s\" contains LF character that is not allowed in the header", ZSTR_VAL(key));
136-
return;
137-
case CONTAINS_CR_ONLY:
138-
zend_value_error("Header \"%s\" contains CR character that is not allowed in the header", ZSTR_VAL(key));
139-
return;
140-
case CONTAINS_CRLF:
141-
zend_value_error("Header \"%s\" contains CRLF characters that are used as a line separator and are not allowed in the header", ZSTR_VAL(key));
142-
return;
143-
case CONTAINS_NULL:
144-
zend_value_error("Header \"%s\" contains NULL character that is not allowed in the header", ZSTR_VAL(key));
145-
return;
146-
default:
147-
// fallback
148-
zend_value_error("Header \"%s\" has invalid format, or contains invalid characters", ZSTR_VAL(key));
149-
return;
150-
}
151-
smart_str_append(s, key);
152-
smart_str_appendl(s, ": ", 2);
153-
smart_str_appends(s, Z_STRVAL_P(val));
154-
smart_str_appendl(s, "\r\n", 2);
155-
break;
156-
case IS_ARRAY:
157-
php_mail_build_headers_elems(s, key, val);
118+
php_mail_header_value_error_type error_type = php_mail_build_headers_check_field_value(val);
119+
switch (error_type) {
120+
case NO_HEADER_ERROR:
158121
break;
122+
case CONTAINS_LF_ONLY:
123+
zend_value_error("Header \"%s\" contains LF character that is not allowed in the header", ZSTR_VAL(key));
124+
return;
125+
case CONTAINS_CR_ONLY:
126+
zend_value_error("Header \"%s\" contains CR character that is not allowed in the header", ZSTR_VAL(key));
127+
return;
128+
case CONTAINS_CRLF:
129+
zend_value_error("Header \"%s\" contains CRLF characters that are used as a line separator and are not allowed in the header", ZSTR_VAL(key));
130+
return;
131+
case CONTAINS_NULL:
132+
zend_value_error("Header \"%s\" contains NULL character that is not allowed in the header", ZSTR_VAL(key));
133+
return;
159134
default:
160-
zend_type_error("Header \"%s\" must be of type array|string, %s given", ZSTR_VAL(key), zend_zval_value_name(val));
135+
// fallback
136+
zend_value_error("Header \"%s\" has invalid format, or contains invalid characters", ZSTR_VAL(key));
137+
return;
161138
}
139+
smart_str_append(s, key);
140+
smart_str_appendl(s, ": ", 2);
141+
smart_str_append(s, val);
142+
smart_str_appendl(s, "\r\n", 2);
162143
}
163144

164-
165-
static void php_mail_build_headers_elems(smart_str *s, zend_string *key, zval *val)
145+
static void php_mail_build_headers_array(smart_str *s, const zend_string *key, const HashTable *val)
166146
{
167147
zend_string *tmp_key;
168148
zval *tmp_val;
169149

170-
ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(val), tmp_key, tmp_val) {
150+
ZEND_HASH_FOREACH_STR_KEY_VAL(val, tmp_key, tmp_val) {
171151
if (tmp_key) {
172152
zend_type_error("Header \"%s\" must only contain numeric keys, \"%s\" found", ZSTR_VAL(key), ZSTR_VAL(tmp_key));
173153
break;
@@ -177,25 +157,11 @@ static void php_mail_build_headers_elems(smart_str *s, zend_string *key, zval *v
177157
zend_type_error("Header \"%s\" must only contain values of type string, %s found", ZSTR_VAL(key), zend_zval_value_name(tmp_val));
178158
break;
179159
}
180-
php_mail_build_headers_elem(s, key, tmp_val);
160+
// TODO Should this actually pass tmp_key?
161+
php_mail_build_headers_elem(s, key, Z_STR_P(tmp_val));
181162
} ZEND_HASH_FOREACH_END();
182163
}
183164

184-
#define PHP_MAIL_BUILD_HEADER_CHECK(target, s, key, val) \
185-
do { \
186-
if (Z_TYPE_P(val) == IS_STRING) { \
187-
php_mail_build_headers_elem(&s, key, val); \
188-
} else if (Z_TYPE_P(val) == IS_ARRAY) { \
189-
if (zend_string_equals_literal_ci(key, target)) { \
190-
zend_type_error("Header \"%s\" must be of type string, array given", target); \
191-
break; \
192-
} \
193-
php_mail_build_headers_elems(&s, key, val); \
194-
} else { \
195-
zend_type_error("Header \"%s\" must be of type array|string, %s given", ZSTR_VAL(key), zend_zval_value_name(val)); \
196-
} \
197-
} while(0)
198-
199165
PHPAPI zend_string *php_mail_build_headers(HashTable *headers)
200166
{
201167
zend_ulong idx;
@@ -206,39 +172,48 @@ PHPAPI zend_string *php_mail_build_headers(HashTable *headers)
206172
ZEND_HASH_FOREACH_KEY_VAL(headers, idx, key, val) {
207173
if (!key) {
208174
zend_type_error("Header name cannot be numeric, " ZEND_LONG_FMT " given", idx);
209-
break;
175+
goto error;
176+
}
177+
if (!php_mail_build_headers_check_field_name(key)) {
178+
zend_value_error("Header name \"%s\" contains invalid characters", ZSTR_VAL(key));
179+
goto error;
210180
}
211181
ZVAL_DEREF(val);
182+
if (UNEXPECTED(Z_TYPE_P(val) != IS_STRING && Z_TYPE_P(val) != IS_ARRAY)) {
183+
zend_type_error("Header \"%s\" must be of type array|string, %s given", ZSTR_VAL(key), zend_zval_value_name(val));
184+
goto error;
185+
}
186+
212187
/* https://tools.ietf.org/html/rfc2822#section-3.6 */
213-
if (zend_string_equals_literal_ci(key, "orig-date")) {
214-
PHP_MAIL_BUILD_HEADER_CHECK("orig-date", s, key, val);
215-
} else if (zend_string_equals_literal_ci(key, "from")) {
216-
PHP_MAIL_BUILD_HEADER_CHECK("from", s, key, val);
217-
} else if (zend_string_equals_literal_ci(key, "sender")) {
218-
PHP_MAIL_BUILD_HEADER_CHECK("sender", s, key, val);
219-
} else if (zend_string_equals_literal_ci(key, "reply-to")) {
220-
PHP_MAIL_BUILD_HEADER_CHECK("reply-to", s, key, val);
221-
} else if (zend_string_equals_literal_ci(key, "to")) {
222-
zend_value_error("The additional headers cannot contain the \"To\" header");
223-
} else if (zend_string_equals_literal_ci(key, "cc")) {
224-
PHP_MAIL_BUILD_HEADER_CHECK("cc", s, key, val);
225-
} else if (zend_string_equals_literal_ci(key, "bcc")) {
226-
PHP_MAIL_BUILD_HEADER_CHECK("bcc", s, key, val);
227-
} else if (zend_string_equals_literal_ci(key, "message-id")) {
228-
PHP_MAIL_BUILD_HEADER_CHECK("message-id", s, key, val);
229-
} else if (zend_string_equals_literal_ci(key, "references")) {
230-
PHP_MAIL_BUILD_HEADER_CHECK("references", s, key, val);
231-
} else if (zend_string_equals_literal_ci(key, "in-reply-to")) {
232-
PHP_MAIL_BUILD_HEADER_CHECK("in-reply-to", s, key, val);
188+
if (
189+
zend_string_equals_literal_ci(key, "orig-date")
190+
|| zend_string_equals_literal_ci(key, "from")
191+
|| zend_string_equals_literal_ci(key, "sender")
192+
|| zend_string_equals_literal_ci(key, "reply-to")
193+
|| zend_string_equals_literal_ci(key, "cc")
194+
|| zend_string_equals_literal_ci(key, "bcc")
195+
|| zend_string_equals_literal_ci(key, "message-id")
196+
|| zend_string_equals_literal_ci(key, "references")
197+
|| zend_string_equals_literal_ci(key, "in-reply-to")
198+
) {
199+
if (UNEXPECTED(Z_TYPE_P(val) == IS_ARRAY)) {
200+
zend_type_error("Header \"%s\" must be of type string, array given", ZSTR_VAL(key));
201+
goto error;
202+
}
203+
ZEND_ASSERT(Z_TYPE_P(val) == IS_STRING);
204+
php_mail_build_headers_elem(&s, key, Z_STR_P(val));
233205
} else if (zend_string_equals_literal_ci(key, "subject")) {
234206
zend_value_error("The additional headers cannot contain the \"Subject\" header");
207+
goto error;
208+
} else if (zend_string_equals_literal_ci(key, "to")) {
209+
zend_value_error("The additional headers cannot contain the \"To\" header");
210+
goto error;
235211
} else {
236212
if (Z_TYPE_P(val) == IS_STRING) {
237-
php_mail_build_headers_elem(&s, key, val);
238-
} else if (Z_TYPE_P(val) == IS_ARRAY) {
239-
php_mail_build_headers_elems(&s, key, val);
213+
php_mail_build_headers_elem(&s, key, Z_STR_P(val));
240214
} else {
241-
zend_type_error("Header \"%s\" must be of type array|string, %s given", ZSTR_VAL(key), zend_zval_value_name(val));
215+
ZEND_ASSERT(Z_TYPE_P(val) == IS_ARRAY);
216+
php_mail_build_headers_array(&s, key, Z_ARRVAL_P(val));
242217
}
243218
}
244219

@@ -253,6 +228,10 @@ PHPAPI zend_string *php_mail_build_headers(HashTable *headers)
253228
smart_str_0(&s);
254229

255230
return s.s;
231+
232+
error:
233+
smart_str_free(&s);
234+
return NULL;
256235
}
257236

258237

0 commit comments

Comments
 (0)