+ /* enable chunked transfer encoding */
+ if (ctx->chunked) {
+ php_http_buffer_appends(&header_buf, "Transfer-Encoding: chunked" PHP_HTTP_CRLF);
+ }
+
+ php_http_buffer_appends(&header_buf, PHP_HTTP_CRLF);
+
+ if (header_buf.used == php_stream_write(ctx->stream, header_buf.data, header_buf.used)) {
+ ctx->started = 1;
+ }
+ php_http_buffer_dtor(&header_buf);
+ php_stream_flush(ctx->stream);
+
+ if (ctx->chunked) {
+ ctx->chunked_filter = php_stream_filter_create("http.chunked_encode", NULL, 0);
+ php_stream_filter_append(&ctx->stream->writefilters, ctx->chunked_filter);
+ }
+
+ return ctx->started ? SUCCESS : FAILURE;
+}
+static long php_http_env_response_stream_get_status(php_http_env_response_t *r)
+{
+ php_http_env_response_stream_ctx_t *ctx = r->ctx;
+
+ return ctx->status_code;
+}
+static ZEND_RESULT_CODE php_http_env_response_stream_set_status(php_http_env_response_t *r, long http_code)
+{
+ php_http_env_response_stream_ctx_t *stream_ctx = r->ctx;
+
+ if (stream_ctx->started || stream_ctx->finished) {
+ return FAILURE;
+ }
+
+ stream_ctx->status_code = http_code;
+
+ return SUCCESS;
+}
+static ZEND_RESULT_CODE php_http_env_response_stream_set_protocol_version(php_http_env_response_t *r, php_http_version_t *v)
+{
+ php_http_env_response_stream_ctx_t *stream_ctx = r->ctx;
+
+ if (stream_ctx->started || stream_ctx->finished) {
+ return FAILURE;
+ }
+
+ memcpy(&stream_ctx->version, v, sizeof(stream_ctx->version));
+
+ return SUCCESS;
+}
+static ZEND_RESULT_CODE php_http_env_response_stream_set_header_ex(php_http_env_response_t *r, zend_bool replace, const char *fmt, va_list argv)
+{
+ php_http_env_response_stream_ctx_t *stream_ctx = r->ctx;
+ char *header_end, *header_str = NULL;
+ size_t header_len = 0;
+ zval zheader, *zheader_ptr;
+ zend_string *header_key;
+ ZEND_RESULT_CODE rv;
+
+ if (stream_ctx->started || stream_ctx->finished) {
+ return FAILURE;
+ }
+
+ header_len = vspprintf(&header_str, 0, fmt, argv);
+
+ if (!(header_end = strchr(header_str, ':'))) {
+ efree(header_str);
+ return FAILURE;
+ }
+
+ header_key = zend_string_init(header_str, header_end - header_str, 0);
+
+ if (!replace && (zheader_ptr = zend_hash_find(&stream_ctx->header, header_key))) {
+ convert_to_array(zheader_ptr);
+ rv = add_next_index_str(zheader_ptr, php_http_cs2zs(header_str, header_len));
+ } else {
+ ZVAL_STR(&zheader, php_http_cs2zs(header_str, header_len));
+
+ rv = zend_hash_update(&stream_ctx->header, header_key, &zheader)
+ ? SUCCESS : FAILURE;
+ }
+
+ zend_string_release(header_key);
+
+ return rv;
+}
+static ZEND_RESULT_CODE php_http_env_response_stream_set_header(php_http_env_response_t *r, const char *fmt, ...)
+{
+ ZEND_RESULT_CODE ret;
+ va_list argv;
+
+ va_start(argv, fmt);
+ ret = php_http_env_response_stream_set_header_ex(r, 1, fmt, argv);
+ va_end(argv);
+
+ return ret;
+}
+static ZEND_RESULT_CODE php_http_env_response_stream_add_header(php_http_env_response_t *r, const char *fmt, ...)
+{
+ ZEND_RESULT_CODE ret;
+ va_list argv;
+
+ va_start(argv, fmt);
+ ret = php_http_env_response_stream_set_header_ex(r, 0, fmt, argv);
+ va_end(argv);
+
+ return ret;
+}
+static ZEND_RESULT_CODE php_http_env_response_stream_del_header(php_http_env_response_t *r, const char *header_str, size_t header_len)
+{
+ php_http_env_response_stream_ctx_t *stream_ctx = r->ctx;
+
+ if (stream_ctx->started || stream_ctx->finished) {
+ return FAILURE;
+ }
+
+ zend_hash_str_del(&stream_ctx->header, header_str, header_len);
+ return SUCCESS;
+}
+static ZEND_RESULT_CODE php_http_env_response_stream_write(php_http_env_response_t *r, const char *data_str, size_t data_len)
+{
+ php_http_env_response_stream_ctx_t *stream_ctx = r->ctx;
+
+ if (stream_ctx->finished) {
+ return FAILURE;
+ }
+ if (!stream_ctx->started) {
+ if (SUCCESS != php_http_env_response_stream_start(stream_ctx)) {
+ return FAILURE;
+ }
+ }
+
+ if (data_len != php_stream_write(stream_ctx->stream, data_str, data_len)) {
+ return FAILURE;
+ }
+
+ return SUCCESS;
+}
+static ZEND_RESULT_CODE php_http_env_response_stream_flush(php_http_env_response_t *r)
+{
+ php_http_env_response_stream_ctx_t *stream_ctx = r->ctx;
+
+ if (stream_ctx->finished) {
+ return FAILURE;
+ }
+ if (!stream_ctx->started) {
+ if (SUCCESS != php_http_env_response_stream_start(stream_ctx)) {
+ return FAILURE;
+ }
+ }
+
+ return php_stream_flush(stream_ctx->stream);
+}
+static ZEND_RESULT_CODE php_http_env_response_stream_finish(php_http_env_response_t *r)