+
+ if (SUCCESS != r->ops->finish(r)) {
+ return FAILURE;
+ }
+
+ return SUCCESS;
+}
+
+static long php_http_env_response_sapi_get_status(php_http_env_response_t *r)
+{
+ TSRMLS_FETCH_FROM_CTX(r->ts);
+
+ return php_http_env_get_response_code(TSRMLS_C);
+}
+static STATUS php_http_env_response_sapi_set_status(php_http_env_response_t *r, long http_code)
+{
+ TSRMLS_FETCH_FROM_CTX(r->ts);
+
+ return php_http_env_set_response_code(http_code TSRMLS_CC);
+}
+static STATUS php_http_env_response_sapi_set_protocol_version(php_http_env_response_t *r, php_http_version_t *v)
+{
+ TSRMLS_FETCH_FROM_CTX(r->ts);
+
+ return php_http_env_set_response_protocol_version(v TSRMLS_CC);
+}
+static STATUS php_http_env_response_sapi_set_header(php_http_env_response_t *r, const char *fmt, ...)
+{
+ STATUS ret;
+ va_list args;
+ TSRMLS_FETCH_FROM_CTX(r->ts);
+
+ va_start(args, fmt);
+ ret = php_http_env_set_response_header_va(0, 1, fmt, args TSRMLS_CC);
+ va_end(args);
+
+ return ret;
+}
+static STATUS php_http_env_response_sapi_add_header(php_http_env_response_t *r, const char *fmt, ...)
+{
+ STATUS ret;
+ va_list args;
+ TSRMLS_FETCH_FROM_CTX(r->ts);
+
+ va_start(args, fmt);
+ ret = php_http_env_set_response_header_va(0, 0, fmt, args TSRMLS_CC);
+ va_end(args);
+
+ return ret;
+}
+static STATUS php_http_env_response_sapi_del_header(php_http_env_response_t *r, const char *header_str, size_t header_len)
+{
+ TSRMLS_FETCH_FROM_CTX(r->ts);
+
+ return php_http_env_set_response_header_value(0, header_str, header_len, NULL, 1 TSRMLS_CC);
+}
+static STATUS php_http_env_response_sapi_write(php_http_env_response_t *r, const char *data_str, size_t data_len)
+{
+ TSRMLS_FETCH_FROM_CTX(r->ts);
+
+ if (0 < PHPWRITE(data_str, data_len)) {
+ return SUCCESS;
+ }
+ return FAILURE;
+}
+static STATUS php_http_env_response_sapi_flush(php_http_env_response_t *r)
+{
+ TSRMLS_FETCH_FROM_CTX(r->ts);
+
+#if PHP_VERSION_ID >= 50400
+ if (php_output_get_level(TSRMLS_C)) {
+ php_output_flush_all(TSRMLS_C);
+ }
+ if (!(php_output_get_status(TSRMLS_C) & PHP_OUTPUT_IMPLICITFLUSH)) {
+ sapi_flush(TSRMLS_C);
+ }
+#else
+ php_end_ob_buffer(1, 1 TSRMLS_CC);
+ sapi_flush(TSRMLS_C);
+#endif
+
+ return SUCCESS;
+}
+static STATUS php_http_env_response_sapi_finish(php_http_env_response_t *r)
+{
+ return SUCCESS;
+}
+
+static php_http_env_response_ops_t php_http_env_response_sapi_ops = {
+ NULL,
+ NULL,
+ php_http_env_response_sapi_get_status,
+ php_http_env_response_sapi_set_status,
+ php_http_env_response_sapi_set_protocol_version,
+ php_http_env_response_sapi_set_header,
+ php_http_env_response_sapi_add_header,
+ php_http_env_response_sapi_del_header,
+ php_http_env_response_sapi_write,
+ php_http_env_response_sapi_flush,
+ php_http_env_response_sapi_finish
+};
+
+PHP_HTTP_API php_http_env_response_ops_t *php_http_env_response_get_sapi_ops(void)
+{
+ return &php_http_env_response_sapi_ops;
+}
+
+typedef struct php_http_env_response_stream_ctx {
+ HashTable header;
+ php_http_version_t version;
+ long status_code;
+
+ php_stream *stream;
+
+ unsigned started:1;
+ unsigned finished:1;
+} php_http_env_response_stream_ctx_t;
+
+static STATUS php_http_env_response_stream_init(php_http_env_response_t *r, void *init_arg)
+{
+ php_http_env_response_stream_ctx_t *ctx;
+ TSRMLS_FETCH_FROM_CTX(r->ts);
+
+ ctx = ecalloc(1, sizeof(*ctx));
+
+ ctx->stream = init_arg;
+ if (SUCCESS != zend_list_addref(ctx->stream->rsrc_id)) {
+ efree(ctx);
+ return FAILURE;
+ }
+ zend_hash_init(&ctx->header, 0, NULL, ZVAL_PTR_DTOR, 0);
+ php_http_version_init(&ctx->version, 1, 1 TSRMLS_CC);
+ ctx->status_code = 200;
+
+ r->ctx = ctx;
+