static int php_ns_sapi_header_handler(sapi_header_struct *sapi_header, sapi_headers_struct *sapi_headers) { char *header_name, *header_content; char *p; header_name = sapi_header->header; header_content = p = strchr(header_name, ':'); if (p) { *p = '\0'; do { header_content++; } while (*header_content == ' '); if (!strcasecmp(header_name, "Content-type")) { Ns_ConnSetTypeHeader(NSG(conn), header_content); } else { Ns_ConnSetHeaders(NSG(conn), header_name, header_content); } *p = ':'; } sapi_free_header(sapi_header); return 0; }
/* * since zend_llist_del_element only remove one matched item once, * we should remove them by ourself */ static void sapi_remove_header(zend_llist *l, char *name, size_t len) { sapi_header_struct *header; zend_llist_element *next; zend_llist_element *current=l->head; while (current) { header = (sapi_header_struct *)(current->data); next = current->next; if (header->header_len > len && header->header[len] == ':' && !strncasecmp(header->header, name, 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; } }
static int php_apache_sapi_header_handler(sapi_header_struct *sapi_header, sapi_header_op_enum op, sapi_headers_struct *sapi_headers) { php_struct *ctx; char *val, *ptr; ctx = SG(server_context); switch(op) { case SAPI_HEADER_DELETE: apr_table_unset(ctx->r->headers_out, sapi_header->header); return 0; case SAPI_HEADER_DELETE_ALL: apr_table_clear(ctx->r->headers_out); return 0; case SAPI_HEADER_ADD: case SAPI_HEADER_REPLACE: val = strchr(sapi_header->header, ':'); if (!val) { sapi_free_header(sapi_header); return 0; } ptr = val; *val = '\0'; do { val++; } while (*val == ' '); if (!strcasecmp(sapi_header->header, "content-type")) ctx->r->content_type = apr_pstrdup(ctx->r->pool, val); else if (!strcasecmp(sapi_header->header, "content-length")) ap_set_content_length(ctx->r, strtol(val, (char **)NULL, 10)); else if (op == SAPI_HEADER_REPLACE) apr_table_set(ctx->r->headers_out, sapi_header->header, val); else apr_table_add(ctx->r->headers_out, sapi_header->header, val); *ptr = ':'; return SAPI_HEADER_ADD; default: return 0; } }
static void sapi_header_add_op(sapi_header_op_enum op, sapi_header_struct *sapi_header) { if (!sapi_module.header_handler || (SAPI_HEADER_ADD & sapi_module.header_handler(sapi_header, op, &SG(sapi_headers)))) { if (op == SAPI_HEADER_REPLACE) { char *colon_offset = strchr(sapi_header->header, ':'); if (colon_offset) { char sav = *colon_offset; *colon_offset = 0; sapi_remove_header(&SG(sapi_headers).headers, sapi_header->header, (int)strlen(sapi_header->header)); *colon_offset = sav; } } zend_llist_add_element(&SG(sapi_headers).headers, (void *) sapi_header); } else { sapi_free_header(sapi_header); } }
SAPI_API int sapi_send_headers(void) { int retval; int ret = FAILURE; if (SG(headers_sent) || SG(request_info).no_headers) { return SUCCESS; } /* Success-oriented. We set headers_sent to 1 here to avoid an infinite loop * in case of an error situation. */ if (SG(sapi_headers).send_default_content_type && sapi_module.send_headers) { uint32_t len = 0; char *default_mimetype = get_default_content_type(0, &len); if (default_mimetype && len) { sapi_header_struct default_header; SG(sapi_headers).mimetype = default_mimetype; default_header.header_len = sizeof("Content-type: ") - 1 + len; default_header.header = emalloc(default_header.header_len + 1); memcpy(default_header.header, "Content-type: ", sizeof("Content-type: ") - 1); memcpy(default_header.header + sizeof("Content-type: ") - 1, SG(sapi_headers).mimetype, len + 1); sapi_header_add_op(SAPI_HEADER_ADD, &default_header); } else { efree(default_mimetype); } SG(sapi_headers).send_default_content_type = 0; } if (Z_TYPE(SG(callback_func)) != IS_UNDEF) { zval cb; ZVAL_COPY_VALUE(&cb, &SG(callback_func)); ZVAL_UNDEF(&SG(callback_func)); sapi_run_header_callback(&cb); zval_ptr_dtor(&cb); } SG(headers_sent) = 1; if (sapi_module.send_headers) { retval = sapi_module.send_headers(&SG(sapi_headers)); } else { retval = SAPI_HEADER_DO_SEND; } switch (retval) { case SAPI_HEADER_SENT_SUCCESSFULLY: ret = SUCCESS; break; case SAPI_HEADER_DO_SEND: { sapi_header_struct http_status_line; char buf[255]; if (SG(sapi_headers).http_status_line) { http_status_line.header = SG(sapi_headers).http_status_line; http_status_line.header_len = (uint32_t)strlen(SG(sapi_headers).http_status_line); } else { http_status_line.header = buf; http_status_line.header_len = slprintf(buf, sizeof(buf), "HTTP/1.0 %d X", SG(sapi_headers).http_response_code); } sapi_module.send_header(&http_status_line, SG(server_context)); } zend_llist_apply_with_argument(&SG(sapi_headers).headers, (llist_apply_with_arg_func_t) sapi_module.send_header, SG(server_context)); if(SG(sapi_headers).send_default_content_type) { sapi_header_struct default_header; sapi_get_default_content_type_header(&default_header); sapi_module.send_header(&default_header, SG(server_context)); sapi_free_header(&default_header); } sapi_module.send_header(NULL, SG(server_context)); ret = SUCCESS; break; case SAPI_HEADER_SEND_FAILED: SG(headers_sent) = 0; ret = FAILURE; break; } sapi_send_headers_free(); return ret; }