calls.
Revert the change to the sapi_add_header_ex interface.
Fix various bugs:
1. header("HTTP/1.0 306 foo");
header("Location: absolute-uri");
did not work in combination with several SAPI modules, because
http_status_line was never properly reset. And thus, all SAPI
modules which looked at http_status_line ignored the changed
http_response_code.
2. The CGI SAPI did not send out the HTTP status line at all, if
http_status_line had not been set explicitly by calling
header("HTTP/1.0 200 foo");
Sends a raw HTTP header */
PHP_FUNCTION(header)
{
- char *header;
- int header_len;
- zend_bool replace = 1;
- int http_code = 0;
+ zend_bool rep = 1;
+ sapi_header_line ctr = {0};
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|bl", &header,
- &header_len, &replace, &http_code) == FAILURE) {
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|bl", &ctr.line,
+ &ctr.line_len, &rep, &ctr.response_code) == FAILURE)
return;
- }
- sapi_add_header_ex(header, header_len, 1, replace, http_code TSRMLS_CC);
+
+ sapi_header_op(rep ? SAPI_HEADER_REPLACE:SAPI_HEADER_ADD, &ctr TSRMLS_CC);
}
/* }}} */
int len=sizeof("Set-Cookie: ");
time_t t;
char *dt;
-
+ sapi_header_line ctr = {0};
+
len += name_len;
if (value) {
int encoded_value_len;
strcat(cookie, "; secure");
}
- return sapi_add_header_ex(cookie, strlen(cookie), 0, 0, 0 TSRMLS_CC);
+ ctr.line = cookie;
+ ctr.line_len = strlen(cookie);
+
+ return sapi_header_op(SAPI_HEADER_ADD, &ctr TSRMLS_CC);
}
return code;
}
+
+static void sapi_update_response_code(int ncode TSRMLS_CC)
+{
+ if (SG(sapi_headers).http_status_line) {
+ efree(SG(sapi_headers).http_status_line);
+ SG(sapi_headers).http_status_line = NULL;
+ }
+ SG(sapi_headers).http_response_code = ncode;
+}
+
static int sapi_find_matching_header(void *element1, void *element2)
{
return strncasecmp(((sapi_header_struct*)element1)->header, (char*)element2, strlen((char*)element2)) == 0;
}
-/* This function expects a *duplicated* string, that was previously emalloc()'d.
- * Pointers sent to this functions will be automatically freed by the framework.
- */
-SAPI_API int sapi_add_header_ex(char *header_line, uint header_line_len, zend_bool duplicate, zend_bool replace, int http_response_code TSRMLS_DC)
+SAPI_API int sapi_add_header_ex(char *header_line, uint header_line_len, zend_bool duplicate, zend_bool replace TSRMLS_DC)
+{
+ sapi_header_line ctr = {0};
+ int r;
+
+ ctr.line = header_line;
+ ctr.line_len = header_line_len;
+
+ r = sapi_header_op(replace ? SAPI_HEADER_REPLACE : SAPI_HEADER_ADD,
+ &ctr TSRMLS_CC);
+
+ if (!duplicate)
+ efree(header_line);
+
+ return r;
+}
+
+SAPI_API int sapi_header_op(sapi_header_op_enum op, void *arg TSRMLS_DC)
{
int retval;
sapi_header_struct sapi_header;
char *colon_offset;
long myuid = 0L;
-
+ char *header_line;
+ uint header_line_len;
+ zend_bool replace;
+ int http_response_code;
+
if (SG(headers_sent) && !SG(request_info).no_headers) {
char *output_start_filename = php_get_output_start_filename(TSRMLS_C);
int output_start_lineno = php_get_output_start_lineno(TSRMLS_C);
if (output_start_filename) {
- sapi_module.sapi_error(E_WARNING, "Cannot add header information - headers already sent by (output started at %s:%d)",
+ sapi_module.sapi_error(E_WARNING, "Cannot modify header information - headers already sent by (output started at %s:%d)",
output_start_filename, output_start_lineno);
} else {
- sapi_module.sapi_error(E_WARNING, "Cannot add header information - headers already sent");
- }
- if (!duplicate) {
- efree(header_line);
+ sapi_module.sapi_error(E_WARNING, "Cannot modify header information - headers already sent");
}
return FAILURE;
}
- if (duplicate) {
- header_line = estrndup(header_line, header_line_len);
+ switch (op) {
+ case SAPI_HEADER_SET_STATUS:
+ sapi_update_response_code((int) arg TSRMLS_CC);
+ return SUCCESS;
+
+ case SAPI_HEADER_REPLACE:
+ case SAPI_HEADER_ADD: {
+ sapi_header_line *p = arg;
+ header_line = p->line;
+ header_line_len = p->line_len;
+ http_response_code = p->response_code;
+ replace = (op == SAPI_HEADER_REPLACE);
+ break;
+ }
+
+ default:
+ return FAILURE;
}
+ header_line = estrndup(header_line, header_line_len);
+
/* cut of trailing spaces, linefeeds and carriage-returns */
while(isspace(header_line[header_line_len-1]))
header_line[--header_line_len]='\0';
if (header_line_len>=5
&& !strncasecmp(header_line, "HTTP/", 5)) {
/* filter out the response code */
- SG(sapi_headers).http_response_code = sapi_extract_response_code(header_line);
+ sapi_update_response_code(sapi_extract_response_code(header_line) TSRMLS_CC);
SG(sapi_headers).http_status_line = header_line;
return SUCCESS;
} else {
if (SG(sapi_headers).http_response_code < 300 ||
SG(sapi_headers).http_response_code > 307) {
/* Return a Found Redirect if one is not already specified */
- SG(sapi_headers).http_response_code = 302;
+ sapi_update_response_code(302 TSRMLS_CC);
}
} else if (!STRCASECMP(header_line, "WWW-Authenticate")) { /* HTTP Authentication */
int newlen;
int ptr_len=0, result_len = 0;
#endif
- SG(sapi_headers).http_response_code = 401; /* authentication-required */
+ sapi_update_response_code(401 TSRMLS_CC); /* authentication-required */
#if HAVE_PCRE || HAVE_BUNDLED_PCRE
if(PG(safe_mode)) {
myuid = php_getuid();
}
}
}
-
if (http_response_code) {
- SG(sapi_headers).http_response_code = http_response_code;
+ sapi_update_response_code(http_response_code TSRMLS_CC);
}
if (sapi_module.header_handler) {
retval = sapi_module.header_handler(&sapi_header, &SG(sapi_headers) TSRMLS_CC);
case SAPI_HEADER_SENT_SUCCESSFULLY:
ret = SUCCESS;
break;
- case SAPI_HEADER_DO_SEND:
- if (SG(sapi_headers).http_status_line) {
+ case SAPI_HEADER_DO_SEND: {
sapi_header_struct http_status_line;
+ char buf[255];
- http_status_line.header = SG(sapi_headers).http_status_line;
- http_status_line.header_len = strlen(SG(sapi_headers).http_status_line);
+ if (SG(sapi_headers).http_status_line) {
+ http_status_line.header = SG(sapi_headers).http_status_line;
+ http_status_line.header_len = strlen(SG(sapi_headers).http_status_line);
+ } else {
+ http_status_line.header = buf;
+ http_status_line.header_len = sprintf(buf, "HTTP/1.0 %d X", SG(sapi_headers).http_response_code);
+ }
sapi_module.send_header(&http_status_line, SG(server_context) TSRMLS_CC);
}
zend_llist_apply_with_argument(&SG(sapi_headers).headers, (llist_apply_with_arg_func_t) sapi_module.send_header, SG(server_context) TSRMLS_CC);
SAPI_API void sapi_deactivate(TSRMLS_D);
SAPI_API void sapi_initialize_empty_request(TSRMLS_D);
-SAPI_API int sapi_add_header_ex(char *header_line, uint header_line_len, zend_bool duplicate, zend_bool replace, int http_response_code TSRMLS_DC);
-#define sapi_add_header(header_line, header_line_len, duplicate) \
- sapi_add_header_ex((header_line), (header_line_len), (duplicate), 1, 0 TSRMLS_CC)
+/*
+ * This is the preferred and maintained API for
+ * operating on HTTP headers.
+ */
+
+/*
+ * Always specify a sapi_header_line this way:
+ *
+ * sapi_header_line ctr = {0};
+ */
+
+typedef struct {
+ char *line; /* If you allocated this, you need to free it yourself */
+ uint line_len;
+ long response_code; /* long due to zend_parse_parameters compatibility */
+} sapi_header_line;
+
+typedef enum { /* Parameter: */
+ SAPI_HEADER_REPLACE, /* sapi_header_line* */
+ SAPI_HEADER_ADD, /* sapi_header_line* */
+ SAPI_HEADER_SET_STATUS /* int */
+} sapi_header_op_enum;
+
+SAPI_API int sapi_header_op(sapi_header_op_enum op, void *arg TSRMLS_DC);
+
+
+/* Deprecated functions. Use sapi_header_op instead. */
+SAPI_API int sapi_add_header_ex(char *header_line, uint header_line_len, zend_bool duplicate, zend_bool replace TSRMLS_DC);
+#define sapi_add_header(a, b, c) sapi_add_header_ex((a),(b),(c),1 TSRMLS_CC)
+
+
SAPI_API int sapi_send_headers(TSRMLS_D);
SAPI_API void sapi_free_header(sapi_header_struct *sapi_header);
SAPI_API void sapi_handle_post(void *arg TSRMLS_DC);
};
};
break;
- case PHP_MODE_INDENT:
- header_line = (char *)estrdup("Content-Type: text/plain");
- sapi_add_header_ex(header_line, strlen(header_line), 1, 1, 0 TSRMLS_CC);
+ case PHP_MODE_INDENT: {
+ sapi_header_line ctr = {0};
+
+ ctr.line = "Content-Type: text/plain";
+ ctr.line_len = strlen(ctr.line);
+
+ sapi_header_op(SAPI_HEADER_REPLACE, &ctr TSRMLS_CC);
+ }
if ( open_file_for_scanning( &file_handle TSRMLS_CC ) == SUCCESS )
{
zend_indent();
{
iRet = PIAPI_ERROR;
};
- efree(header_line);
break;
case PHP_MODE_LINT:
iRet = (php_lint_script(&file_handle TSRMLS_CC) == SUCCESS) ?
{
char buf[BUF_SIZE + 1];
char *p;
-
+ sapi_header_line ctr = {0};
+
+ ctr.line = buf;
+ ctr.line_len = sprintf(buf, "Server: %s", TUXAPI_version);
+ sapi_header_op(SAPI_HEADER_REPLACE, &ctr TSRMLS_CC);
- sprintf(buf, "Server: %s", TUXAPI_version);
- sapi_add_header_ex(buf, strlen(buf), 1, 0, 0 TSRMLS_CC);
php_register_variable("PHP_SELF", SG(request_info).request_uri, track_vars_array TSRMLS_CC);
php_register_variable("SERVER_SOFTWARE", TUXAPI_version, track_vars_array TSRMLS_CC);
php_register_variable("GATEWAY_INTERFACE", "CGI/1.1", track_vars_array TSRMLS_CC);
return bytes;
}
-static int sapi_webjames_send_headers(sapi_headers_struct *sapi_headers TSRMLS_DC)
-/*send the HTTP response line*/
-{
- char buf[256];
-
- if (WG(conn)->flags.outputheaders) {
- if (!SG(sapi_headers).http_status_line) {
- int code=SG(sapi_headers).http_response_code;
- snprintf(buf, 255, "HTTP/1.0 %d %s\r\n", code, code==200 ? "OK" : code==302 ? "Moved temporarily" : "Something");
- webjames_writestring(WG(conn), buf);
- }
- }
-
- return SAPI_HEADER_DO_SEND;
-}
-
static void sapi_webjames_send_header(sapi_header_struct *sapi_header, void *server_context TSRMLS_DC)
/*send an HTTP header*/
{
php_error, /* error handler */
NULL, /* header handler */
- sapi_webjames_send_headers, /* send headers handler */
+ NULL, /* send headers handler */
sapi_webjames_send_header, /* send header handler */
sapi_webjames_read_post, /* read POST data */
sapi_webjames_read_cookies, /* read Cookies */