diff --git a/ext/session/session.c b/ext/session/session.c index 7b677249fb41b..5cc5d963059d0 100644 --- a/ext/session/session.c +++ b/ext/session/session.c @@ -1335,46 +1335,18 @@ static int php_session_cache_limiter(void) * Cookie Management * ********************* */ -/* - * Remove already sent session ID cookie. - * It must be directly removed from SG(sapi_header) because sapi_add_header_ex() - * removes all of matching cookie. i.e. It deletes all of Set-Cookie headers. - */ static void php_session_remove_cookie(void) { - sapi_header_struct *header; - zend_llist *l = &SG(sapi_headers).headers; - zend_llist_element *next; - zend_llist_element *current; char *session_cookie; - size_t session_cookie_len; - size_t len = sizeof("Set-Cookie")-1; + sapi_header_line header_line = {0}; ZEND_ASSERT(strpbrk(PS(session_name), SESSION_FORBIDDEN_CHARS) == NULL); spprintf(&session_cookie, 0, "Set-Cookie: %s=", PS(session_name)); - session_cookie_len = strlen(session_cookie); - current = l->head; - while (current) { - header = (sapi_header_struct *)(current->data); - next = current->next; - if (header->header_len > len && header->header[len] == ':' - && !strncmp(header->header, session_cookie, session_cookie_len)) { - if (current->prev) { - current->prev->next = next; - } else { - l->head = next; - } - if (next) { - next->prev = current->prev; - } else { - l->tail = current->prev; - } - sapi_free_header(header); - efree(current); - --l->count; - } - current = next; - } + header_line.line = session_cookie; + header_line.line_len = strlen(session_cookie); + header_line.header_len = sizeof("Set-Cookie") - 1; + sapi_header_op(SAPI_HEADER_DELETE_PREFIX, &header_line); + efree(session_cookie); } diff --git a/main/SAPI.c b/main/SAPI.c index 866b44c3eac7d..169ae572fa967 100644 --- a/main/SAPI.c +++ b/main/SAPI.c @@ -597,7 +597,8 @@ static void sapi_update_response_code(int ncode) * since zend_llist_del_element only removes one matched item once, * we should remove them manually */ -static void sapi_remove_header(zend_llist *l, char *name, size_t len) { +static void sapi_remove_header(zend_llist *l, char *name, size_t len, size_t header_len) +{ sapi_header_struct *header; zend_llist_element *next; zend_llist_element *current=l->head; @@ -605,7 +606,8 @@ static void sapi_remove_header(zend_llist *l, char *name, size_t len) { while (current) { header = (sapi_header_struct *)(current->data); next = current->next; - if (header->header_len > len && header->header[len] == ':' + if (header->header_len > header_len + && (header->header[header_len] == ':' || len > header_len) && !strncasecmp(header->header, name, len)) { if (current->prev) { current->prev->next = next; @@ -653,7 +655,7 @@ static void sapi_header_add_op(sapi_header_op_enum op, sapi_header_struct *sapi_ char sav = *colon_offset; *colon_offset = 0; - sapi_remove_header(&SG(sapi_headers).headers, sapi_header->header, strlen(sapi_header->header)); + sapi_remove_header(&SG(sapi_headers).headers, sapi_header->header, strlen(sapi_header->header), 0); *colon_offset = sav; } } @@ -668,7 +670,7 @@ SAPI_API int sapi_header_op(sapi_header_op_enum op, void *arg) sapi_header_struct sapi_header; char *colon_offset; char *header_line; - size_t header_line_len; + size_t header_line_len, header_len; int http_response_code; if (SG(headers_sent) && !SG(request_info).no_headers) { @@ -691,6 +693,7 @@ SAPI_API int sapi_header_op(sapi_header_op_enum op, void *arg) case SAPI_HEADER_ADD: case SAPI_HEADER_REPLACE: + case SAPI_HEADER_DELETE_PREFIX: case SAPI_HEADER_DELETE: { sapi_header_line *p = arg; @@ -699,7 +702,13 @@ SAPI_API int sapi_header_op(sapi_header_op_enum op, void *arg) } header_line = estrndup(p->line, p->line_len); header_line_len = p->line_len; - http_response_code = p->response_code; + if (op == SAPI_HEADER_DELETE_PREFIX) { + header_len = p->header_len; + http_response_code = 0; + } else { + header_len = 0; + http_response_code = p->response_code; + } break; } @@ -722,8 +731,8 @@ SAPI_API int sapi_header_op(sapi_header_op_enum op, void *arg) header_line[header_line_len]='\0'; } - if (op == SAPI_HEADER_DELETE) { - if (strchr(header_line, ':')) { + if (op == SAPI_HEADER_DELETE || op == SAPI_HEADER_DELETE_PREFIX) { + if (op == SAPI_HEADER_DELETE && strchr(header_line, ':')) { efree(header_line); sapi_module.sapi_error(E_WARNING, "Header to delete may not contain colon."); return FAILURE; @@ -733,7 +742,7 @@ SAPI_API int sapi_header_op(sapi_header_op_enum op, void *arg) sapi_header.header_len = header_line_len; sapi_module.header_handler(&sapi_header, op, &SG(sapi_headers)); } - sapi_remove_header(&SG(sapi_headers).headers, header_line, header_line_len); + sapi_remove_header(&SG(sapi_headers).headers, header_line, header_line_len, header_len); efree(header_line); return SUCCESS; } else { diff --git a/main/SAPI.h b/main/SAPI.h index 284f4cb96f1fa..a5e2d70df7209 100644 --- a/main/SAPI.h +++ b/main/SAPI.h @@ -185,13 +185,17 @@ END_EXTERN_C() typedef struct { const char *line; /* If you allocated this, you need to free it yourself */ size_t line_len; - zend_long response_code; /* long due to zend_parse_parameters compatibility */ + union { + zend_long response_code; /* long due to zend_parse_parameters compatibility */ + size_t header_len; /* the "Key" in "Key: Value", for optimization */ + }; } sapi_header_line; typedef enum { /* Parameter: */ SAPI_HEADER_REPLACE, /* sapi_header_line* */ SAPI_HEADER_ADD, /* sapi_header_line* */ SAPI_HEADER_DELETE, /* sapi_header_line* */ + SAPI_HEADER_DELETE_PREFIX, /* sapi_header_line* */ SAPI_HEADER_DELETE_ALL, /* void */ SAPI_HEADER_SET_STATUS /* int */ } sapi_header_op_enum; @@ -199,7 +203,6 @@ typedef enum { /* Parameter: */ BEGIN_EXTERN_C() SAPI_API int sapi_header_op(sapi_header_op_enum op, void *arg); -/* Deprecated functions. Use sapi_header_op instead. */ SAPI_API int sapi_add_header_ex(const char *header_line, size_t header_line_len, bool duplicate, bool replace); #define sapi_add_header(a, b, c) sapi_add_header_ex((a),(b),(c),1)