diff --git a/ext-src/php_swoole_http.h b/ext-src/php_swoole_http.h index 9844c49fe39..535871c34db 100644 --- a/ext-src/php_swoole_http.h +++ b/ext-src/php_swoole_http.h @@ -187,8 +187,11 @@ struct Context { bool set_header(const char *, size_t, zval *, bool); bool set_header(const char *, size_t, const char *, size_t, bool); void end(zval *zdata, zval *return_value); + bool send_file(const char *file, uint32_t l_file, off_t offset, size_t length); void send_trailer(zval *return_value); String *get_write_buffer(); + void build_header(String *http_buffer, size_t body_length); + ssize_t build_trailer(String *http_buffer); #ifdef SW_HAVE_COMPRESSION void set_compression_method(const char *accept_encoding, size_t length); @@ -197,6 +200,7 @@ struct Context { #ifdef SW_USE_HTTP2 void http2_end(zval *zdata, zval *return_value); + bool http2_send_file(const char *file, uint32_t l_file, off_t offset, size_t length); #endif void free(); diff --git a/ext-src/swoole_http2_server.cc b/ext-src/swoole_http2_server.cc index c84ef5e0f38..3aafafbbc99 100644 --- a/ext-src/swoole_http2_server.cc +++ b/ext-src/swoole_http2_server.cc @@ -36,7 +36,7 @@ using Http2Session = Http2::Session; static std::unordered_map http2_sessions; extern String *swoole_http_buffer; -static bool swoole_http2_server_respond(HttpContext *ctx, String *body); +static bool http2_server_respond(HttpContext *ctx, String *body); Http2Stream::Stream(Http2Session *client, uint32_t _id) { ctx = swoole_http_context_new(client->fd); @@ -100,7 +100,7 @@ static void http2_server_send_window_update(HttpContext *ctx, uint32_t stream_id ctx->send(ctx, frame, SW_HTTP2_FRAME_HEADER_SIZE + SW_HTTP2_WINDOW_UPDATE_SIZE); } -static ssize_t http2_build_trailer(HttpContext *ctx, uchar *buffer) { +static ssize_t http2_server_build_trailer(HttpContext *ctx, uchar *buffer) { zval *ztrailer = sw_zend_read_property_ex(swoole_http_response_ce, ctx->response.zobject, SW_ZSTR_KNOWN(SW_ZEND_STR_TRAILER), 0); uint32_t size = php_swoole_array_length_safe(ztrailer); @@ -151,7 +151,7 @@ static ssize_t http2_build_trailer(HttpContext *ctx, uchar *buffer) { return 0; } -static bool swoole_http2_is_static_file(Server *serv, HttpContext *ctx) { +static bool http2_server_is_static_file(Server *serv, HttpContext *ctx) { zval *zserver = ctx->request.zserver; zval *zrequest_uri = zend_hash_str_find(Z_ARR_P(zserver), ZEND_STRL("request_uri")); if (zrequest_uri && Z_TYPE_P(zrequest_uri) == IS_STRING) { @@ -164,7 +164,7 @@ static bool swoole_http2_is_static_file(Server *serv, HttpContext *ctx) { String null_body = {}; ctx->response.status = SW_HTTP_NOT_FOUND; - swoole_http2_server_respond(ctx, &null_body); + http2_server_respond(ctx, &null_body); return true; } @@ -196,7 +196,7 @@ static bool swoole_http2_is_static_file(Server *serv, HttpContext *ctx) { return false; } -static void swoole_http2_onRequest(Http2Session *client, Http2Stream *stream) { +static void http2_server_onRequest(Http2Session *client, Http2Stream *stream) { HttpContext *ctx = stream->ctx; zval *zserver = ctx->request.zserver; Server *serv = (Server *) ctx->private_data; @@ -205,9 +205,9 @@ static void swoole_http2_onRequest(Http2Session *client, Http2Stream *stream) { int server_fd = conn->server_fd; Connection *serv_sock = serv->get_connection(server_fd); - ctx->request.version = SW_HTTP_OK; + ctx->request.version = SW_HTTP_VERSION_2; - if (serv->enable_static_handler && swoole_http2_is_static_file(serv, ctx)) { + if (serv->enable_static_handler && http2_server_is_static_file(serv, ctx)) { zval_ptr_dtor(ctx->request.zobject); zval_ptr_dtor(ctx->response.zobject); return; @@ -234,13 +234,30 @@ static void swoole_http2_onRequest(Http2Session *client, Http2Stream *stream) { zval_ptr_dtor(&args[1]); } -static ssize_t http2_build_header(HttpContext *ctx, uchar *buffer, size_t body_length) { +static void http2_server_set_date_header(Http2::HeaderSet *headers) { + static struct { + time_t time; + size_t len; + char buf[64]; + } cache{}; + + time_t now = time(nullptr); + if (now != cache.time) { + char *date_str = php_swoole_format_date((char *) ZEND_STRL(SW_HTTP_DATE_FORMAT), now, 0); + cache.len = strlen(date_str); + memcpy(cache.buf, date_str, cache.len); + cache.time = now; + efree(date_str); + } + headers->add(ZEND_STRL("date"), cache.buf, cache.len); +} + +static ssize_t http2_server_build_header(HttpContext *ctx, uchar *buffer, size_t body_length) { zval *zheader = sw_zend_read_property_ex(swoole_http_response_ce, ctx->response.zobject, SW_ZSTR_KNOWN(SW_ZEND_STR_HEADER), 0); zval *zcookie = sw_zend_read_property_ex(swoole_http_response_ce, ctx->response.zobject, SW_ZSTR_KNOWN(SW_ZEND_STR_COOKIE), 0); Http2::HeaderSet headers(32 + php_swoole_array_length_safe(zheader) + php_swoole_array_length_safe(zcookie)); - char *date_str = nullptr; char intbuf[2][16]; int ret; @@ -306,15 +323,11 @@ static ssize_t http2_build_header(HttpContext *ctx, uchar *buffer, size_t body_l headers.add(ZEND_STRL("server"), ZEND_STRL(SW_HTTP_SERVER_SOFTWARE)); } if (!(header_flags & HTTP_HEADER_DATE)) { - date_str = php_swoole_format_date((char *) ZEND_STRL(SW_HTTP_DATE_FORMAT), time(nullptr), 0); - headers.add(ZEND_STRL("date"), date_str, strlen(date_str)); + http2_server_set_date_header(&headers); } if (!(header_flags & HTTP_HEADER_CONTENT_TYPE)) { headers.add(ZEND_STRL("content-type"), ZEND_STRL("text/html")); } - if (date_str) { - efree(date_str); - } // cookies if (ZVAL_IS_ARRAY(zcookie)) { @@ -400,7 +413,7 @@ int swoole_http2_server_goaway(HttpContext *ctx, zend_long error_code, const cha bool Http2Stream::send_header(size_t body_length, bool end_stream) { char header_buffer[SW_BUFFER_SIZE_STD]; - ssize_t bytes = http2_build_header(ctx, (uchar *) header_buffer, body_length); + ssize_t bytes = http2_server_build_header(ctx, (uchar *) header_buffer, body_length); if (bytes < 0) { return false; } @@ -479,7 +492,6 @@ bool Http2Stream::send_body(String *body, bool end_stream, size_t max_frame_size swoole_trace_log( SW_TRACE_HTTP2, "send [" SW_ECHO_YELLOW "] stream_id=%u, flags=%d, send_n=%lu", "DATA", id, flags, send_n); - l -= send_n; p += send_n; } @@ -492,7 +504,7 @@ bool Http2Stream::send_trailer() { char frame_header[SW_HTTP2_FRAME_HEADER_SIZE]; swoole_http_buffer->clear(); - ssize_t bytes = http2_build_trailer(ctx, (uchar *) header_buffer); + ssize_t bytes = http2_server_build_trailer(ctx, (uchar *) header_buffer); if (bytes > 0) { http2::set_frame_header( frame_header, SW_HTTP2_TYPE_HEADERS, bytes, SW_HTTP2_FLAG_END_HEADERS | SW_HTTP2_FLAG_END_STREAM, id); @@ -506,7 +518,7 @@ bool Http2Stream::send_trailer() { return true; } -static bool swoole_http2_server_respond(HttpContext *ctx, String *body) { +static bool http2_server_respond(HttpContext *ctx, String *body) { Http2Session *client = http2_sessions[ctx->fd]; Http2Stream *stream = ctx->stream; @@ -569,10 +581,13 @@ static bool swoole_http2_server_respond(HttpContext *ctx, String *body) { _end_stream = true && end_stream; } - error = !stream->send_body(body, _end_stream, client->local_settings.max_frame_size, body->offset, send_len); + error = + !stream->send_body(body, _end_stream, client->local_settings.max_frame_size, body->offset, send_len); if (!error) { - swoole_trace_log( - SW_TRACE_HTTP2, "body: send length=%zu, stream->remote_window_size=%u", send_len, stream->remote_window_size); + swoole_trace_log(SW_TRACE_HTTP2, + "body: send length=%zu, stream->remote_window_size=%u", + send_len, + stream->remote_window_size); body->offset += send_len; if (send_len > stream->remote_window_size) { @@ -602,20 +617,19 @@ static bool swoole_http2_server_respond(HttpContext *ctx, String *body) { return !error; } -static bool http2_context_sendfile(HttpContext *ctx, const char *file, uint32_t l_file, off_t offset, size_t length) { - Http2Session *client = http2_sessions[ctx->fd]; - Http2Stream *stream = (Http2Stream *) ctx->stream; +bool HttpContext::http2_send_file(const char *file, uint32_t l_file, off_t offset, size_t length) { + Http2Session *client = http2_sessions[fd]; std::shared_ptr body; #ifdef SW_HAVE_COMPRESSION - ctx->accept_compression = 0; + accept_compression = 0; #endif if (swoole_coroutine_is_in()) { body = System::read_file(file, false); if (!body) { return false; } - if (!ctx->stream) { + if (!stream) { /* closed */ return false; } @@ -632,13 +646,17 @@ static bool http2_context_sendfile(HttpContext *ctx, const char *file, uint32_t body->length = SW_MIN(length, body->length); zval *ztrailer = - sw_zend_read_property_ex(swoole_http_response_ce, ctx->response.zobject, SW_ZSTR_KNOWN(SW_ZEND_STR_TRAILER), 0); + sw_zend_read_property_ex(swoole_http_response_ce, response.zobject, SW_ZSTR_KNOWN(SW_ZEND_STR_TRAILER), 0); if (php_swoole_array_length_safe(ztrailer) == 0) { ztrailer = nullptr; } - const char *mimetype = swoole::mime_type::get(file).c_str(); - ctx->set_header(ZEND_STRL("content-type"), mimetype, strlen(mimetype), 0); + zval *zheader = + sw_zend_read_and_convert_property_array(swoole_http_response_ce, response.zobject, ZEND_STRL("header"), 0); + if (!zend_hash_str_exists(Z_ARRVAL_P(zheader), ZEND_STRL("content-type"))) { + const char *mimetype = swoole::mime_type::get(file).c_str(); + set_header(ZEND_STRL("content-type"), mimetype, strlen(mimetype), 0); + } bool end_stream = (ztrailer == nullptr); if (!stream->send_header(length, end_stream)) { @@ -646,7 +664,7 @@ static bool http2_context_sendfile(HttpContext *ctx, const char *file, uint32_t } /* headers has already been sent, retries are no longer allowed (even if send body failed) */ - ctx->end_ = 1; + end_ = 1; bool error = false; @@ -665,7 +683,7 @@ static bool http2_context_sendfile(HttpContext *ctx, const char *file, uint32_t } if (error) { - ctx->close(ctx); + close(this); } else { client->streams.erase(stream->id); delete stream; @@ -674,7 +692,7 @@ static bool http2_context_sendfile(HttpContext *ctx, const char *file, uint32_t return true; } -static int http2_parse_header(Http2Session *client, HttpContext *ctx, int flags, const char *in, size_t inlen) { +static int http2_server_parse_header(Http2Session *client, HttpContext *ctx, int flags, const char *in, size_t inlen) { nghttp2_hd_inflater *inflater = client->inflater; if (!inflater) { @@ -861,7 +879,7 @@ int swoole_http2_server_parse(Http2Session *client, const char *buf) { swoole_trace_log(SW_TRACE_HTTP2, "setting: max_frame_size=%u", value); break; case SW_HTTP2_SETTINGS_MAX_HEADER_LIST_SIZE: - client->remote_settings.max_header_list_size = value; // useless now + client->remote_settings.max_header_list_size = value; // useless now swoole_trace_log(SW_TRACE_HTTP2, "setting: max_header_list_size=%u", value); break; default: @@ -892,7 +910,7 @@ int swoole_http2_server_parse(Http2Session *client, const char *buf) { } else { ctx = stream->ctx; } - if (http2_parse_header(client, ctx, flags, buf, length) < 0) { + if (http2_server_parse_header(client, ctx, flags, buf, length) < 0) { return SW_ERR; } @@ -1039,7 +1057,7 @@ int swoole_http2_server_onReceive(Server *serv, Connection *conn, RecvData *req) client = new Http2Session(session_id); } - client->handle = swoole_http2_onRequest; + client->handle = http2_server_onRequest; if (!client->default_ctx) { client->default_ctx = new HttpContext(); client->default_ctx->init(serv); @@ -1047,7 +1065,6 @@ int swoole_http2_server_onReceive(Server *serv, Connection *conn, RecvData *req) client->default_ctx->http2 = true; client->default_ctx->stream = (Http2Stream *) -1; client->default_ctx->keepalive = true; - client->default_ctx->sendfile = http2_context_sendfile; } zval zdata; @@ -1076,7 +1093,7 @@ void HttpContext::http2_end(zval *zdata, zval *return_value) { http_body.str = nullptr; } - RETURN_BOOL(swoole_http2_server_respond(this, &http_body)); + RETURN_BOOL(http2_server_respond(this, &http_body)); } #endif diff --git a/ext-src/swoole_http_response.cc b/ext-src/swoole_http_response.cc index 71961971349..591fb086eb4 100644 --- a/ext-src/swoole_http_response.cc +++ b/ext-src/swoole_http_response.cc @@ -41,9 +41,6 @@ namespace HttpServer = swoole::http_server; zend_class_entry *swoole_http_response_ce; static zend_object_handlers swoole_http_response_handlers; -static void http_build_header(HttpContext *ctx, String *response, size_t body_length); -static ssize_t http_build_trailer(HttpContext *ctx, String *response); - static inline void http_header_key_format(char *key, int length) { int i, state = 0; for (i = 0; i < length; i++) { @@ -307,7 +304,7 @@ static PHP_METHOD(swoole_http_response, write) { if (!ctx->send_header_) { ctx->send_chunked = 1; http_buffer->clear(); - http_build_header(ctx, http_buffer, 0); + ctx->build_header(http_buffer, 0); if (!ctx->send(ctx, http_buffer->str, http_buffer->length)) { ctx->send_chunked = 0; ctx->send_header_ = 0; @@ -364,23 +361,39 @@ static bool parse_header_flags(HttpContext *ctx, const char *key, size_t keylen, return true; } -static void http_build_header(HttpContext *ctx, String *response, size_t body_length) { +static void http_set_date_header(String *response) { + static struct { + time_t time; + size_t len; + char buf[64]; + } cache{}; + + time_t now = time(nullptr); + if (now != cache.time) { + char *date_str = php_swoole_format_date((char *) ZEND_STRL(SW_HTTP_DATE_FORMAT), now, 0); + cache.len = sw_snprintf(cache.buf, sizeof(cache.buf), "Date: %s\r\n", date_str); + efree(date_str); + cache.time = now; + } + response->append(cache.buf, cache.len); +} + +void HttpContext::build_header(String *http_buffer, size_t body_length) { char *buf = sw_tg_buffer()->str; size_t l_buf = sw_tg_buffer()->size; int n; - char *date_str; - assert(ctx->send_header_ == 0); + assert(send_header_ == 0); /** * http status line */ - if (!ctx->response.reason) { - n = sw_snprintf(buf, l_buf, "HTTP/1.1 %s\r\n", HttpServer::get_status_message(ctx->response.status)); + if (!response.reason) { + n = sw_snprintf(buf, l_buf, "HTTP/1.1 %s\r\n", HttpServer::get_status_message(response.status)); } else { - n = sw_snprintf(buf, l_buf, "HTTP/1.1 %d %s\r\n", ctx->response.status, ctx->response.reason); + n = sw_snprintf(buf, l_buf, "HTTP/1.1 %d %s\r\n", response.status, response.reason); } - response->append(buf, n); + http_buffer->append(buf, n); uint32_t header_flags = 0x0; @@ -388,14 +401,14 @@ static void http_build_header(HttpContext *ctx, String *response, size_t body_le * http header */ zval *zheader = - sw_zend_read_property_ex(swoole_http_response_ce, ctx->response.zobject, SW_ZSTR_KNOWN(SW_ZEND_STR_HEADER), 0); + sw_zend_read_property_ex(swoole_http_response_ce, response.zobject, SW_ZSTR_KNOWN(SW_ZEND_STR_HEADER), 0); if (ZVAL_IS_ARRAY(zheader)) { const char *key; uint32_t keylen; int type; zval *zvalue; - auto add_header = [](swoole::String *response, const char *key, size_t l_key, zval *value) { + auto add_header = [](String *response, const char *key, size_t l_key, zval *value) { if (ZVAL_IS_NULL(value)) { return; } @@ -415,17 +428,17 @@ static void http_build_header(HttpContext *ctx, String *response, size_t body_le if (UNEXPECTED(!key || ZVAL_IS_NULL(zvalue))) { continue; } - if (!parse_header_flags(ctx, key, keylen, header_flags)) { + if (!parse_header_flags(this, key, keylen, header_flags)) { continue; } if (ZVAL_IS_ARRAY(zvalue)) { zval *zvalue_2; SW_HASHTABLE_FOREACH_START(Z_ARRVAL_P(zvalue), zvalue_2) { - add_header(response, key, keylen, zvalue_2); + add_header(http_buffer, key, keylen, zvalue_2); } SW_HASHTABLE_FOREACH_END(); } else { - add_header(response, key, keylen, zvalue); + add_header(http_buffer, key, keylen, zvalue); } } SW_HASHTABLE_FOREACH_END(); @@ -434,87 +447,84 @@ static void http_build_header(HttpContext *ctx, String *response, size_t body_le // http cookies zval *zcookie = - sw_zend_read_property_ex(swoole_http_response_ce, ctx->response.zobject, SW_ZSTR_KNOWN(SW_ZEND_STR_COOKIE), 0); + sw_zend_read_property_ex(swoole_http_response_ce, response.zobject, SW_ZSTR_KNOWN(SW_ZEND_STR_COOKIE), 0); if (ZVAL_IS_ARRAY(zcookie)) { zval *zvalue; SW_HASHTABLE_FOREACH_START(Z_ARRVAL_P(zcookie), zvalue) { if (Z_TYPE_P(zvalue) != IS_STRING) { continue; } - response->append(ZEND_STRL("Set-Cookie: ")); - response->append(Z_STRVAL_P(zvalue), Z_STRLEN_P(zvalue)); - response->append(ZEND_STRL("\r\n")); + http_buffer->append(ZEND_STRL("Set-Cookie: ")); + http_buffer->append(Z_STRVAL_P(zvalue), Z_STRLEN_P(zvalue)); + http_buffer->append(ZEND_STRL("\r\n")); } SW_HASHTABLE_FOREACH_END(); } if (!(header_flags & HTTP_HEADER_SERVER)) { - response->append(ZEND_STRL("Server: " SW_HTTP_SERVER_SOFTWARE "\r\n")); + http_buffer->append(ZEND_STRL("Server: " SW_HTTP_SERVER_SOFTWARE "\r\n")); } // websocket protocol (subsequent header info is unnecessary) - if (ctx->upgrade == 1) { - response->append(ZEND_STRL("\r\n")); - ctx->send_header_ = 1; + if (upgrade == 1) { + http_buffer->append(ZEND_STRL("\r\n")); + send_header_ = 1; return; } if (!(header_flags & HTTP_HEADER_CONNECTION)) { - if (ctx->keepalive) { - response->append(ZEND_STRL("Connection: keep-alive\r\n")); + if (keepalive) { + http_buffer->append(ZEND_STRL("Connection: keep-alive\r\n")); } else { - response->append(ZEND_STRL("Connection: close\r\n")); + http_buffer->append(ZEND_STRL("Connection: close\r\n")); } } if (!(header_flags & HTTP_HEADER_CONTENT_TYPE)) { - response->append(ZEND_STRL("Content-Type: text/html\r\n")); + http_buffer->append(ZEND_STRL("Content-Type: text/html\r\n")); } if (!(header_flags & HTTP_HEADER_DATE)) { - date_str = php_swoole_format_date((char *) ZEND_STRL(SW_HTTP_DATE_FORMAT), time(nullptr), 0); - n = sw_snprintf(buf, l_buf, "Date: %s\r\n", date_str); - response->append(buf, n); - efree(date_str); + http_set_date_header(http_buffer); } - if (ctx->send_chunked) { + if (send_chunked) { SW_ASSERT(body_length == 0); if (!(header_flags & HTTP_HEADER_TRANSFER_ENCODING)) { - response->append(ZEND_STRL("Transfer-Encoding: chunked\r\n")); + http_buffer->append(ZEND_STRL("Transfer-Encoding: chunked\r\n")); } } // Content-Length - else if (body_length > 0 || ctx->parser.method != PHP_HTTP_HEAD) { + else if (body_length > 0 || parser.method != PHP_HTTP_HEAD) { #ifdef SW_HAVE_COMPRESSION - if (ctx->accept_compression) { + if (accept_compression) { body_length = swoole_zlib_buffer->length; } #endif if (!(header_flags & HTTP_HEADER_CONTENT_LENGTH)) { n = sw_snprintf(buf, l_buf, "Content-Length: %zu\r\n", body_length); - response->append(buf, n); + http_buffer->append(buf, n); } } #ifdef SW_HAVE_COMPRESSION // http compress - if (ctx->accept_compression) { - const char *content_encoding = ctx->get_content_encoding(); - response->append(ZEND_STRL("Content-Encoding: ")); - response->append((char *) content_encoding, strlen(content_encoding)); - response->append(ZEND_STRL("\r\n")); + if (accept_compression) { + const char *content_encoding = get_content_encoding(); + http_buffer->append(ZEND_STRL("Content-Encoding: ")); + http_buffer->append((char *) content_encoding, strlen(content_encoding)); + http_buffer->append(ZEND_STRL("\r\n")); } #endif - response->append(ZEND_STRL("\r\n")); - ctx->send_header_ = 1; + http_buffer->append(ZEND_STRL("\r\n")); + send_header_ = 1; } -static ssize_t http_build_trailer(HttpContext *ctx, String *response) { +ssize_t HttpContext::build_trailer(String *http_buffer) { char *buf = sw_tg_buffer()->str; size_t l_buf = sw_tg_buffer()->size; int n; ssize_t ret = 0; zval *ztrailer = - sw_zend_read_property_ex(swoole_http_response_ce, ctx->response.zobject, SW_ZSTR_KNOWN(SW_ZEND_STR_TRAILER), 0); + sw_zend_read_property_ex(swoole_http_response_ce, response.zobject, SW_ZSTR_KNOWN(SW_ZEND_STR_TRAILER), 0); uint32_t size = php_swoole_array_length_safe(ztrailer); if (size > 0) { @@ -532,13 +542,13 @@ static ssize_t http_build_trailer(HttpContext *ctx, String *response) { zend::String str_value(zvalue); n = sw_snprintf( buf, l_buf, "%.*s: %.*s\r\n", (int) keylen, key, (int) str_value.len(), str_value.val()); - response->append(buf, n); + http_buffer->append(buf, n); ret += n; } } SW_HASHTABLE_FOREACH_END(); (void) type; - response->append(ZEND_STRL("\r\n")); + http_buffer->append(ZEND_STRL("\r\n")); } return ret; @@ -718,7 +728,7 @@ void HttpContext::send_trailer(zval *return_value) { String *http_buffer = get_write_buffer(); http_buffer->clear(); - if (http_build_trailer(this, http_buffer) == 0) { + if (build_trailer(http_buffer) == 0) { return; } if (!send(this, http_buffer->str, http_buffer->length)) { @@ -728,6 +738,41 @@ void HttpContext::send_trailer(zval *return_value) { } } +bool HttpContext::send_file(const char *file, uint32_t l_file, off_t offset, size_t length) { + zval *zheader = + sw_zend_read_and_convert_property_array(swoole_http_response_ce, response.zobject, ZEND_STRL("header"), 0); + if (!zend_hash_str_exists(Z_ARRVAL_P(zheader), ZEND_STRL("Content-Type"))) { + add_assoc_string(zheader, "Content-Type", (char *) swoole::mime_type::get(file).c_str()); + } + + if (!send_header_) { +#ifdef SW_HAVE_COMPRESSION + accept_compression = 0; +#endif + String *http_buffer = get_write_buffer(); + http_buffer->clear(); + + build_header(http_buffer, length); + + if (!send(this, http_buffer->str, http_buffer->length)) { + send_header_ = 0; + return false; + } + } + + if (length > 0 && !sendfile(this, file, l_file, offset, length)) { + close(this); + return false; + } + + end_ = 1; + + if (!keepalive) { + close(this); + } + return true; +} + void HttpContext::end(zval *zdata, zval *return_value) { struct { char *str; @@ -768,7 +813,7 @@ void HttpContext::end(zval *zdata, zval *return_value) { } } #endif - http_build_header(this, http_buffer, http_body.length); + build_header(http_buffer, http_body.length); char *send_body_str; size_t send_body_len; @@ -912,44 +957,13 @@ static PHP_METHOD(swoole_http_response, sendfile) { } #ifdef SW_USE_HTTP2 - if (!ctx->http2) -#endif - if (!ctx->send_header_) { -#ifdef SW_HAVE_COMPRESSION - ctx->accept_compression = 0; + if (ctx->http2) { + RETURN_BOOL(ctx->http2_send_file(file, l_file, offset, length)); + } else #endif - String *http_buffer = ctx->get_write_buffer(); - - http_buffer->clear(); - - zval *zheader = sw_zend_read_and_convert_property_array( - swoole_http_response_ce, ctx->response.zobject, ZEND_STRL("header"), 0); - if (!zend_hash_str_exists(Z_ARRVAL_P(zheader), ZEND_STRL("Content-Type"))) { - add_assoc_string(zheader, "Content-Type", (char *) swoole::mime_type::get(file).c_str()); - } - - http_build_header(ctx, http_buffer, length); - - if (!ctx->send(ctx, http_buffer->str, http_buffer->length)) { - ctx->send_header_ = 0; - RETURN_FALSE; - } - } - - if (length != 0) { - if (!ctx->sendfile(ctx, file, l_file, offset, length)) { - ctx->close(ctx); - RETURN_FALSE; - } - } - - ctx->end_ = 1; - - if (!ctx->keepalive) { - ctx->close(ctx); + { + RETURN_BOOL(ctx->send_file(file, l_file, offset, length)); } - - RETURN_TRUE; } static void php_swoole_http_response_cookie(INTERNAL_FUNCTION_PARAMETERS, const bool url_encode) { diff --git a/ext-src/swoole_http_server.cc b/ext-src/swoole_http_server.cc index a7e1bc55e56..35841c328da 100644 --- a/ext-src/swoole_http_server.cc +++ b/ext-src/swoole_http_server.cc @@ -15,6 +15,7 @@ */ #include "php_swoole_http_server.h" +#include "swoole_process_pool.h" using namespace swoole; using swoole::coroutine::Socket; @@ -59,6 +60,7 @@ int php_swoole_http_server_onReceive(Server *serv, RecvData *req) { if (conn->websocket_status == WebSocket::STATUS_ACTIVE) { return swoole_websocket_onMessage(serv, req); } + #ifdef SW_USE_HTTP2 if (conn->http2_stream) { return swoole_http2_server_onReceive(serv, conn, req); @@ -88,9 +90,7 @@ int php_swoole_http_server_onReceive(Server *serv, RecvData *req) { size_t parsed_n = ctx->parse(Z_STRVAL_P(zdata), Z_STRLEN_P(zdata)); if (ctx->parser.state == s_dead) { -#ifdef SW_HTTP_BAD_REQUEST_PACKET ctx->send(ctx, SW_STRL(SW_HTTP_BAD_REQUEST_PACKET)); -#endif ctx->close(ctx); swoole_notice("request is illegal and it has been discarded, %ld bytes unprocessed", Z_STRLEN_P(zdata) - parsed_n);